Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

sprintf invalid format '%d'

Tags:

c

r

printf

coercion

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?

like image 303
pomber Avatar asked Nov 24 '14 14:11

pomber


People also ask

What is the declaration for sprintf () function in C?

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.

How do you format a string in sprintf?

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.

What is int sprintf in C programming?

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.

Why can't I write precision in sprintf?

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.


1 Answers

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.

like image 134
Mikael Jumppanen Avatar answered Oct 08 '22 00:10

Mikael Jumppanen