2014-11-24 11 views
14

Questo funziona:sprintf formato non valido '% d'

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

e questo non lo fa:

> 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 

Perché?

+0

So che potrei usare qualcosa come 'sprintf ('% .f', c (1.5, 1))' ma voglio capire cosa sta succedendo con '% d' – pomber

+3

Sto meditando su [sprintf. c] (https://svn.r-project.org/R/trunk/src/main/sprintf.c), finora è difficile dire esattamente perché il comportamento è asimmetrico. C'è un commento sul tentativo di coercizione su 'ns = 0', anche se il codice che lo circonda è criptico. – tonytonov

+0

@RichardScriven cosa c'è nel file della guida? – pomber

risposta

9

Questa è una domanda davvero interessante. Per iniziare, %d è l'acronimo di integer. L'argomento vettore viene riciclato se possibile, ma se è c(1.5, 1) fallirà quando sprintf() tenta di sostituire %d con 1.5 (che non è intero).

ho pensato che potrebbe essere correlato al fatto che R sia intero e doppio sono modo numerico, ad esempio:

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" 

Pertanto entrambe vettori devono essere conservati come doppia. Maggiori informazioni su vettore in R language definition e nella documentazione per ? numeric:

Il potenziale confusione è che R è la modalità "numerica" ​​usato per indicare 'doppio o un numero intero'"

ho potuto trovare il linee in the underlying C code che spiegano cosa sta succedendo:

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

Questo codice effettua le seguenti operazioni: Se il tipo di vettore è REALSXP (che significa numerico) quindi convertire primo membro del vettore a double r. Quindi inserire r come numero intero e quindi doppio e se i byte sono ancora uguali, convertire l'intero vettore come INTSXP. È importante sottolineare che questo codice controlla solo il primo elemento di un vettore; se quell'elemento può essere convertito in intero, allora l'intero vettore viene forzato, altrimenti il ​​codice dà un errore.

Per verificare questa ipotesi si potrebbe compilare R con un costume sprintf() dove double r = REAL(_this)[0]; viene modificato in double r = REAL(_this)[1]; e verificare se c(1.5, 1) opere ora o meno.

+0

Spiacente, non capisco come questo spieghi le differenze tra 'c (1.5, 1)' e 'c (1, 1.5)' – pomber

+0

La risposta esatta può essere trovata probabilmente da qui: [rsource/sprintf. c] (https://github.com/SurajGupta/r-source/blob/46102b91b35a7befa0cf6cc6abd0da09b86f1621/src/main/sprintf.c). Se qualcuno con più esperienza con C potrebbe trovarlo? –

+0

Ottima risposta, implementazione bizzarra. Deve essere stato fatto in questo modo per motivi di prestazioni. – pomber