Деление на ноль в Haskell
я обнаружил довольно странное несоответствие между поведением div
и /
.
*ghci> :t 1 `div` 0
1 `div` 0 :: Integral a => a
*ghci> :t 1 / 0
1 / 0 :: Fractional a => a
*ghci> 1 / 0
Infinity
*ghci> 1 `div` 0
*** Exception: divide by zero
Я был очень удивлен, заметив, что дробное деление на ноль приводит к Infinity
, тогда как div
правильно приводит к исключение.
А NaN
может быть приемлемым для /
, но почему Infinity
? Для такого результата нет математического обоснования. Вы знаете причину этого, пожалуйста?
4 ответов
причина div
не возвращает Infinity
просто-нет представления для бесконечности в Integer
тип.
/
возвращает Infinity
потому что он следует стандарту IEEE 754 (который описывает представления чисел с плавающей запятой), так как по умолчанию Fractional
тип Double
. Другие языки с числами с плавающей запятой (например, JavaScript) также демонстрируют такое поведение.
чтобы заставить математиков съежиться еще больше, вы получаете другой результат если разделить на отрицательный 0, несмотря на то, что -0 == 0
для поплавков:
Prelude> 1/(-0)
-Infinity
это также поведение от стандарта.
если вы используете другой частичный типа Rational
, вы получите поведение, которое вы ожидаете:
Prelude> 1 / (0 :: Rational)
*** Exception: Ratio.%: zero denominator
по совпадению, если вам интересно, почему Integer
и Double
являются ли типы, о которых идет речь, когда ваша фактическая операция не ссылается на них, посмотрите, как Haskell обрабатывает типы по умолчанию (особенно числовые типы) в отчет.
короткая версия заключается в том, что если у вас есть неоднозначный тип от Num
класс, Хаскелл сначала попробовать Integer
а то Double
для этого типа. Вы можете изменить это с помощью default (Type1, Type2...)
заявление или выключить его с помощью default ()
оператор на уровне модуля.
это может быть не так по математической причине. Infinity
иногда используется как "ящик греха": все, что не работает в нашей системе чисто, поместите его туда.
пример:
Prelude> 10 ** 10 ** 10
Infinity
... определенно не математически оправдано!
частичная не равно типу Float (или Double).
дробь 1/n, где n переходит в 0, поэтому lim(n→0) 1/n = +∞, lim (n→0) -1/n= -∞, и это имеет смысл.