Компиляционная платформа принимает режим округления ФПУ во внимание в печати, преобразования

StackOverflow https://stackoverflow.com/questions/2595563

Вопрос

Редактировать: Я допустил ошибку во время сеанса отладки, которая приведет меня, чтобы задать этот вопрос. Различия, которые я видел, были на самом деле в печати двойной и разбавивающей двойной (strtod). Ответ Стивена по-прежнему хорошо охватывает мой вопрос даже после этого исправления, поэтому я думаю, что я оставлю этот вопрос в том случае, если это полезно для кого-то.

Некоторые (большинство) C Compilation платформ у меня есть доступ, чтобы не принимать во внимание режим окружающей среды FPU, когда

  • преобразование 64-разрядного целочисленного double;
  • Печать А. double.

Здесь нет ничего не экзотического: Mac OS X Leopard, различные последние варианты Linux и BSD, Windows.

С другой стороны, Mac OS X Snow Leopard, кажется, учитывает режим округления при выполнении этих двух вещей. Конечно, разное поведение раздражает меня не конец.

Вот типичные фрагменты для двух случаев:

#if defined(__OpenBSD__) || defined(__NetBSD__) 
# include <ieeefp.h>
# define FE_UPWARD FP_RP
# define fesetround(RM) fpsetround(RM)
#else 
# include <fenv.h>
#endif

#include <float.h>
#include <math.h>

fesetround(FE_UPWARD);

...
double f;
long long b = 2000000001;
b = b*b;
f = b;

...
printf("%f\n", 0.1);

Мои вопросы:

  1. Есть ли что-то не уродливое, что я могу сделать, чтобы нормализовать поведение по всем платформам? Некоторые скрытые настройки, чтобы сказать платформам, которые принимают режим округления во внимание не или наоборот?
  2. Является одним из стандартных поведений?
  3. Что я могу столкнуться, когда режим окружения ФПУ не используется? Раунд к нулю? Раунд до ближайшего? Пожалуйста, скажите мне, что есть только одна альтернатива :)

Что касается 2. Я нашел место в стандарте, где говорится, что поплавки, преобразованные в целые числа, всегда усечены (округлые к нулю), но я не мог найти ничего для целого числа -> направления поплавка.

Это было полезно?

Решение

Если вы не установили режим округления, он должен быть режим IEEE-754 по умолчанию, который является кругом к ближайшему.

Для преобразований из целочисленного на плавать, стандарт C говорит (§6.3.1.4):

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

Таким образом, оба поведения соответствуют стандарту C.

Стандарт C говорит (§f.5), что конверсии между форматами плавающих точек IEC60559 и последовательностями символов будут правильно округлены согласно стандарту IEEE-754. Для форматов не IEC60559 это рекомендуется, но не требуется. Стандарт IEEEE-754 1985 года (пункт 5.4):

Конверсии должны быть правильно округляются, как указано в разделе 4 для операндов, лежащих в диапазонах, указанных в таблице 3. В противном случае для округления до ближайшего, ошибка в преобразованном результате не должна превышать более чем 0,47 единиц в наименьшую значительную цифру пункт назначения. То, что понесено в окружающие спецификации раздела 4, при условии, что показатель по сравнению с преобразованием не происходит. В направленных режимах округления ошибка должна иметь правильный знак и не должен превышать 1,47 единиц в последнем месте.

В каком сечении (4) на самом деле говорится, что операция должна происходить в соответствии с преобладающим режимом округления. Т.е. если вы измените режим округления, IEEE-754 говорит, что результат поплавок-> конверсии строки должен меняться соответственно. То же самое для целочисленных -> поплавок преобразования.

Ревизия 2008 года стандарт IEEE-754 говорит (пункт 4.3):

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

Оба преобразования определены как вычислительные операции в пункте 5, поэтому опять они должны выполняться в соответствии с преобладающим режимом округления.

Я бы утвердовал, что снежный леопард имеет правильное поведение здесь (предполагая, что это правильно Округление результатов в соответствии с преобладающим режимом округления). Если вы хотите заставить старое поведение, вы всегда можете обернуть printf Вызывает в код, который меняет режим округления, я полагаю, хотя это явно не идеально.

В качестве альтернативы вы можете использовать %a Формат спецификатора (шестнадцатеричная плавающая точка) на C99 Соответствующие платформы. Поскольку результат этого преобразования всегда точен, он никогда не будет осуществляться преобладающим режимом округления. Я не думаю, что библиотека Windows C поддерживает %a, но вы, вероятно, можете легко портировать реализацию BSD или Glibc, если вам это нужно.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top