Подтвердить что ты не робот

Абсолютное значение отрицательного нуля - ошибка или часть стандарта с плавающей запятой?

Я знаю, что подписанные нули используются, чтобы отличать нижний поток от положительных или отрицательных чисел, и поэтому стоит их отличить. Интуитивно я чувствую, что абсолютное значение -0.0 должно быть 0.0. Однако это не то, что говорит Хаскелл:

Prelude> abs (-0.0)
-0.0

Для чего это стоит, Python 2.7 не согласен:

>>> -0.0
-0.0
>>> abs(-0.0)
0.0

Является ли это ошибкой или частью стандарта?

4b9b3361

Ответ 1

Поведение, которое вы описываете, определенно не соответствует стандарту IEEE 754, который в своем последнем воплощении говорит:

abs (x) копирует операнд с плавающей запятой x в пункт назначения в том же формат, установив бит знака в 0 (положительный).

Это в разделе 5.5.1 IEEE 754-2008, озаглавленном "Сигнальные операции с битами". Хотя я не могу дать ссылку на сам стандарт, вы можете увидеть примерно такой же язык в последнем доступном публичном проекте стандарта, в раздел 7.5.1. (В целом стандарт значительно отличается от этого черновика, но этот бит почти не изменился.)

Это не делает его ошибкой в ​​Haskell, если только Haskell не утверждает, что соответствует стандарту IEEE 754, и, кроме того, утверждает, что реализация abs в прелюдии должна отображаться в функции IEEE 754 abs. Стандарт просто требует, чтобы операция abs была предоставлена, но ничего не говорит о том, как она может быть записана.

Ответ 2

Это поведение, определенное в отчете Haskell.

6.4.4 Величина и знак

Число имеет величину и знак. Функции abs и signum применимы к любому числу и удовлетворяют закону:

abs x * signum x == x

Для действительных чисел эти функции определяются:

abs x    | x >= 0  = x  
         | x <  0  = -x  

signum x | x >  0  = 1  
         | x == 0  = 0  
         | x <  0  = -1

Поскольку отрицательный ноль равен нулю, -0.0 >= 0 истинно, поэтому abs (-0.0) = -0.0. Это также согласуется с определением signum, так как -0.0 * 0.0 = -0.0.

Ответ 3

Как сказано в стандарте IEEE, 0 == (-0), хотя у них разные знаки. Это вполне разумно, ничто по-прежнему ничего не значит, что вы используете. Это означает, что

let nzero = (-0.0)
    a = abs nzero
in a == 0.0 && a == nzero

оценивается как True, потому что на самом деле это то же самое, что abs x == 0 или abs x == (-0). Несмотря на то, что это сомнительный выбор, мне кажется, что abs (-0.0) == (-0.0) не является ошибкой для меня.

Edit: Как отмечают комментарии, show 0.0 /= show (-0.0). Я не уверен, как это оправдать. Единственное, что мне пришло в голову, это то, что, возможно, Eq не представляет собой ограничивающий контракт в отношении ссылочной прозрачности, например. два значения типа не должны быть представлены таким же образом, чтобы их можно было считать равнозначными.

Я напишу обновление, как только смогу найти некоторые ссылки о том, как Eq должен быть создан.