math - División por cero en Haskell
division divide-by-zero (4)
Encontré una inconsistencia bastante extraña entre el comportamiento de div
y /
.
*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
Me sorprendió bastante notar que la división fraccionada por cero conduce al Infinity
, mientras que div
conduce correctamente a una excepción. Un NaN
podría ser aceptable también para /
, pero ¿por qué Infinity
? No hay justificación matemática para tal resultado. ¿Sabes la razón de esto, por favor?
Espero que esto ayude:
Prelude> 1/0
Infinity
Prelude> -1/0
-Infinity
Prelude> 0/0
NaN
Fraccional no es igual al tipo Flotante (o Doble).
Fracción de 1 / n donde n va a 0, entonces lim (n → 0) 1 / n = + ∞, lim (n → 0) -1 / n = -∞ y eso tiene sentido.
La razón por la que div
no devuelve Infinity
es simple: no hay representación para infinito en el tipo Integer
.
/
devuelve Infinity
porque sigue el estándar IEEE 754 (que describe las representaciones de número de punto flotante) ya que el tipo Fractional
predeterminado es Double
. Otros idiomas con números de punto flotante (por ejemplo, JavaScript) también exhiben este comportamiento.
Para hacer que los matemáticos se hundan aún más, obtienes un resultado diferente si divides entre 0 negativo , a pesar del hecho de que -0 == 0
para flotadores:
Prelude> 1/(-0)
-Infinity
Este es también el comportamiento de la norma.
Si usa un tipo fraccional diferente como Rational
, obtendrá el comportamiento que espera:
Prelude> 1 / (0 :: Rational)
*** Exception: Ratio.%: zero denominator
Casualmente, si se pregunta por qué Integer
y Double
son los tipos en cuestión cuando su operación real no hace referencia a ellos, observe cómo Haskell maneja los tipos predeterminados (especialmente los tipos numéricos) en el report .
La versión corta es que si tiene un tipo ambiguo de la clase Num
, Haskell probará primero con Integer
y luego con Double
para ese tipo. Puede cambiar esto con una declaración default (Type1, Type2...)
o desactivarla con una instrucción default ()
en el nivel del módulo.
Puede que no sea así por una razón matemática. Infinity
se usa a veces como un "sin bin": todo lo que no funciona de manera limpia en nuestro sistema, póngalo ahí.
Ejemplo:
Prelude> 10 ** 10 ** 10
Infinity
... definitivamente no está justificado matemáticamente!