Абсолютное значение отрицательного нуля - ошибка или часть стандарта с плавающей запятой?
Я знаю, что подписанные нули используются, чтобы отличать нижний поток от положительных или отрицательных чисел, и поэтому стоит их отличить. Интуитивно я чувствую, что абсолютное значение -0.0
должно быть 0.0
. Однако это не то, что говорит Хаскелл:
Prelude> abs (-0.0)
-0.0
Для чего это стоит, Python 2.7 не согласен:
>>> -0.0
-0.0
>>> abs(-0.0)
0.0
Является ли это ошибкой или частью стандарта?
Ответы
Ответ 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
должен быть создан.