Округление различий в системах Windows и Unix в sprintf - PullRequest
10 голосов
/ 10 января 2011

У меня проблема в системах на основе UNIX. Sprintf неправильно округляет значение.

Например,

double tmp = 88888888888885.875
char out[512];

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

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

sprintf(out, "%021.2f", tmp);
printf("out = %s\n", tmp);

В Windows это приводит к:

out = 000088888888888885.88

Включено, например, в AIX, но в Linux также показано:

out = 000088888888888885.87

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

Спасибо

Ответы [ 4 ]

1 голос
/ 11 января 2011

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

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

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

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

1 голос
/ 10 января 2011

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

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

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

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

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

0 голосов
/ 10 января 2011

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

0 голосов
/ 10 января 2011

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

Подробнее в аналогичном вопросе , в блогах или в википедии .

...