Неверный формат 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

Почему?

Ответы

Ответ 1

Это действительно интересный вопрос. Для начала %d означает целое число. Если возможно, векторный аргумент перерабатывается, но если он c(1.5, 1), он потерпит неудачу, когда sprintf() попытается заменить %d на 1,5 (что не является целым числом).

Я думал, что это может быть связано с тем, что в 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 и в документации для ? numeric:

Потенциальная путаница заключается в том, что R использовал режим "числовой" для обозначения "двойное или целое число"

Возможно, я нашел строки в базовом C-коде, которые объясняют, что происходит:

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

Этот код выполняет следующие действия: если векторный тип REALSXP (что означает числовое), то преобразовать первый элемент вектора в double r. Затем нарисуйте r как целое, а затем удвоите, и если байты все равно будут конвертировать весь вектор в качестве INTSXP. Важно отметить, что этот код проверяет только первый элемент вектора; если этот элемент может быть принудительно привязан к целому числу, тогда весь вектор принудительно, иначе код дает ошибку.

Чтобы проверить эту гипотезу, можно скомпилировать R с пользовательским sprintf(), где double r = REAL(_this)[0]; изменено на double r = REAL(_this)[1]; и проверить, работает ли c(1.5, 1) сейчас или нет.