This works:
> sprintf('%d', c(1, 1.5))
[1] "1" "1"
and this doesn't:
> 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
Why?
Following is the declaration for sprintf () function. int sprintf(char *str, const char *format, ...) str − This is the pointer to an array of char elements where the resulting C string is stored.
str = sprintf(formatSpec,A1,...,An) formats the data in arrays A1,...,An using the formatting operators specified by formatSpec and returns the resulting text in str. The sprintf function formats the values in A1,...,An in column order. If formatSpec is a string, then so is the output str.
int sprintf(char *str, const char *format, ...) str − This is the pointer to an array of char elements where the resulting C string is stored. format − This is the String that contains the text to be written to buffer.
The reading functions do not support a precision field. The width field specifies a minimum for writing, but a maximum for reading. If you specify an invalid formatting operator or special character, then sprintf prints all text up to the invalid operator or character and discards the rest.
This is actually really interesting question. To start, %d
stands for integer. The vector argument is recycled if possible but if it is c(1.5, 1)
it will fail when sprintf()
tries to replace %d
with 1.5 (which is not integer).
I thought it might be related to the fact that in R both integer and double are numeric mode, for example:
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"
Thus both vectors should be stored as double. More info about vector in R language definition and in the documentation for ? numeric
:
The potential confusion is that R has used mode "numeric" to mean ‘double or integer’"
I might have found the lines in the underlying C code which explain what is going on:
if(TYPEOF(_this) == REALSXP) {
double r = REAL(_this)[0];
if((double)((int) r) == r)
_this = coerceVector(_this, INTSXP);
This code does the following: If the vector type is REALSXP
(which means numeric) then convert first member of vector to double r
. Then cast r
as integer and then double and if bytes are still same convert whole vector as INTSXP
. Importantly, this code only checks the first element of a vector; if that element can be coerced to integer, then the whole vector is coerced, otherwise the code gives an error.
To test this hypothesis one could compile R with a custom sprintf()
where double r = REAL(_this)[0];
is changed to double r = REAL(_this)[1];
and test whether c(1.5, 1)
works now or not.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With