Деление на ноль в Хаскеле - PullRequest
24 голосов
/ 20 февраля 2012

Я обнаружил довольно странное несоответствие между поведением 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 правильно приводит к исключению.A NaN тоже может быть приемлемым для /, но почему Infinity?Нет математического обоснования такого результата.Вы знаете причину этого, пожалуйста?

Ответы [ 4 ]

41 голосов
/ 20 февраля 2012

Причина, по которой 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, Haskell сначала попытается Integer, а затем Double для этого типа. Вы можете изменить это с помощью оператора default (Type1, Type2...) или отключить его с помощью оператора default () на уровне модуля.

6 голосов
/ 20 февраля 2012

Надеюсь, это поможет:

Prelude> 1/0
Infinity
Prelude> -1/0
-Infinity
Prelude> 0/0
NaN
5 голосов
/ 20 февраля 2012

Это может быть не так по математической причине. Infinity иногда используется как «мусорное ведро»: все, что не работает в нашей системе чисто, поместите это туда.

Пример:

Prelude> 10 ** 10 ** 10
Infinity

... определенно математически не оправдано!

3 голосов
/ 20 февраля 2012

Дробный не равен типу с плавающей точкой (или Double).

Дробь 1 / n, где n переходит в 0, поэтому lim (n → 0) 1 / n = + ∞, lim (n → 0) -1 / n = -∞, и это имеет смысл.

...