2014-11-24 85 views
14

這工作:sprintf的格式無效 '%d'

> sprintf('%d', c(1, 1.5)) 
[1] "1" "1" 

,這並不:

> sprintf('%d', c(1.5, 1)) 
Error in sprintf("%d", c(1.5, 1)) : 
    invalid format '%d'; use format %f, %e, %g or %a for numeric objects 

爲什麼?

+0

我知道我可以使用類似'sprintf('%。f',c(1.5,1))''但我想了解'%d'' – pomber 2014-11-24 14:53:47

+3

我在思考[sprintf。 c](https://svn.r-project.org/R/trunk/src/main/sprintf.c),到目前爲止很難說出爲什麼這種行爲是不對稱的。在'ns = 0'處有一個關於強制嘗試的評論,儘管它周圍的代碼是神祕的。 – tonytonov 2014-11-24 15:28:38

+0

@RichardScriven幫助文件中的內容是什麼? – pomber 2014-11-24 22:00:41

回答

9

這實際上是一個非常有趣的問題。首先,%d代表整數。如果可能的話,矢量參數將被回收,但如果它是c(1.5, 1),則sprintf()試圖用1.5(不是整數)代替%d時將失敗。

我認爲這可能與這樣的事實中的R整數和雙是數字模式,例如:

storage.mode(c(1.5, 1)) 
# [1] "double" 
storage.mode(c(1, 1.5)) 
# [1] "double" 
mode(c(1,1.5)) 
# [1] "numeric" 
mode(c(1.5,1)) 
# [1] "numeric" 

因此,兩個向量應該被存儲爲兩倍。關於向量R language definition? numeric文檔中的更多信息:

潛在的困惑是,R已經使用模式「數字」是指「雙或整數」」

我可能已經找到了在the underlying C code哪一行解釋正在發生的事情:

if(TYPEOF(_this) == REALSXP) { 
double r = REAL(_this)[0]; 
if((double)((int) r) == r) 
_this = coerceVector(_this, INTSXP); 

此代碼執行以下操作:如果載體類型是REALSXP(這意味着數值)再轉換矢量的第一個成員到double r。然後將r轉換爲整數,然後加倍,如果字節仍然相同,則將整個向量轉換爲INTSXP。重要的是,這段代碼只檢查向量的第一個元素;如果該元素可以被強制爲整數,則整個向量被強制,否則代碼會給出錯誤。

爲了檢驗這一假設,人們可以用自定義sprintf(),其中double r = REAL(_this)[0];改爲double r = REAL(_this)[1];編譯R和現在還是不測試是否c(1.5, 1)作品。

+0

對不起,我不明白這是如何解釋'c(1.5,1)'和'c(1,1.5)' – pomber 2014-11-24 21:59:59

+0

之間的區別。可以從這裏找到Excact答案:[rsource/sprintf。 C](https://github.com/SurajGupta/r-source/blob/46102b91b35a7befa0cf6cc6abd0da09b86f1621/src/main/sprintf.c)。如果有更多C經驗的人可以找到它? – 2014-11-24 22:22:13

+0

很好的回答,奇怪的實現。出於性能原因,必須這樣做。 – pomber 2014-11-26 01:41:32