Субтрактивные тождества с плавающей точкой - PullRequest
2 голосов
/ 26 сентября 2019

Насколько я понимаю, в IEEE с плавающей точкой действительно всегда применяется следующая идентификация:

x - 0.0 == x

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

0.0 - x == -x

Это правильно?

Ответы [ 2 ]

4 голосов
/ 26 сентября 2019

(+ 0) - (+0) возвращает (−0) при округлении до −∞, но (+0) во всех других режимах округления.Таким образом, замена x - 0.0 на x даст побитовые идентичные результаты , только если исключен режим округления в сторону −∞ («вниз»).Однако, поскольку (-0) и (+0) сравниваются равными в семантике IEEE-754, x - 0.0 == x будет выполняться во всех режимах округления.

- (+ 0) приводит к (−0), тогда как (+0) - (+0) возвращает (+0) во всех режимах округления, кроме случаев округления в сторону −∞.Таким образом, замена 0.0 - x на -x даст побитовые идентичные результаты только тогда, когда режим округления приближается к −∞ («вниз»).Однако, поскольку (-0) и (+0) сравниваются равными в семантике IEEE-754, 0.0 -x == -x будет выполняться во всех режимах округления.

Что касается побитового равенства (а не равенства с плавающей запятой)сравнения), следует также отметить, что в IEEE-754 (2008) операция negate (например, операции абсолютное значение и copysign )определяется в терминах манипулирования битовой строкой и поэтому изменяет «знаковый бит» NaN (см. раздел 6.3 стандарта).Поэтому на платформах, в которых реализована передача полезных нагрузок NaN, результаты отрицания и вычитания из нуля отличаются на уровне битов, если x является NaN.

3 голосов
/ 26 сентября 2019

Ответ Нюффы дает хороший анализ.В итоге, если вы просто используете ==, который не различает +0 и -0, и если вы игнорируете значения NaN, обе идентичности сохраняются.Но вы можете отличить выражения на основе режима округления, взглянув на битовые комбинации, так как вы можете получить -0 в одном случае и 0 в другом.

Вот еще один пример, который я всегда находилудивительно.Рассмотрим определение fma:

fma (a, b, c) = a * b + c; but with only one rounding instead of two

Если вы введете c = 0 в указанном выше тождестве, вы можете ожидать, что будет выполнено следующее:

fma (a, b, 0) == a * b

Увы, это не удастсяесли умножение генерирует -0, так как -0 + 0 равно +0.С левой стороны вы получите +0, с правой стороны вы получите -0.

Опять же, они будут сравниваться равными, используя обычный ==, но если выВы заинтересованы в побитовом равенстве, вы должны остерегаться знака ноль!

...