Округление различий в системе 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
на некоторых системах.