Округление различий в системе Windows против Unix в sprintf

у меня проблема с UNIX - системами sprintf не округляет должным образом значение.

double tmp = 88888888888885.875
char out[512];

это 88,888,888,888,885.875 просто для удобства глаз. Я даю такой конкретный и большой пример, потому что кажется, что он отлично работает на меньших числах.

Я пытаюсь использовать его следующим образом

sprintf(out, "%021.2f", tmp);
printf("out = %sn", tmp);

в windows это приводит к:

out = 000088888888888885.88

On например AIX, но показывает в Linux как хорошо:

out = 000088888888888885.87

Почему это происходит? Любые идеи и как заставить его вести себя одинаково на Win / Unix

спасибо

4 ответов


есть сообщить об ошибке для glibc с проблемой, очень похожей на вашу. Основной вывод (в комментарии 46) здесь заключается в том, что double не является 15-десятичным числом, и вы не должны ожидать, что он будет работать так.

в качестве обходного пути вы можете добавить что-то небольшое к своим номерам, чтобы сделать их лучше. Но это решение не является общим, потому что оно зависит от диапазонов чисел, с которыми вы имеете дело.

другой обходной путь может быть умножением, чтобы подготовить их для округление, затем округление (например,2597.625*100 = 259762.5 -> 259763 = 2597.63*100)

однако я думаю, что должны быть более умные обходные пути.


какие представления с плавающей запятой используются вашим процессором и компилятором?

Не все процессоры используют один и тот же способ представления значений с плавающей запятой, и даже компиляторы могут выбирать разные методы представления с плавающей запятой (я думаю, что компилятор Microsoft c++ даже имеет опции для выбора представления).

страница http://www.quadibloc.com/comp/cp0201.htm дает обзор некоторых представлений с плавающей запятой (хотя они кажутся довольно старыми архитектурами, показанными там).

http://msdn.microsoft.com/en-us/library/0b34tf65.aspx описывает, как Microsoft Visual C++ хранит значения с плавающей запятой. Я не мог сразу найти, какое представление используется AIX или Linux.

Additinally, каждый компилятор имеет параметры, которые позволяют указать, как вы хотите работать с операциями с плавающей запятой. Вы хотите, чтобы они были правильными, насколько это возможно (но, возможно, несколько медленнее)? Или сделать вы хотите, чтобы операции с плавающей запятой были максимально быстрыми (но, возможно, менее правильными)?


это потому, что вы используете double который имеет ограничения точности, что означает, ваш 88888888888885.875 вероятно, округляется до чего-то еще внутри.

Посмотреть подробнее в аналогичном вопросе, в блоги или Википедия.


в соответствии с реализацией IEEE 754 он должен печатать 88888888888885.88 в режиме округления по умолчанию. Это не имеет ничего общего с точностью с плавающей запятой, так как значение точно представимо; это просто вопрос printfс округлением до 2 знаков после запятой. Понятия не имею, почему вы видите 88888888888885.87 на некоторых системах.