Error de coma flotante de Haskell
-
22-07-2019 - |
Pregunta
Así que he terminado de crear mi propio tipo de datos de números complejos en Haskell.
También, gracias a otra pregunta aquí, obtuve una función que resolverá una ecuación cuadrática.
El único problema ahora es que el código genera un error de análisis en los abrazos, cuando se intenta resolver una cuadrática con raíces complejas.
es decir En abrazos ...
Main> solve (Q 1 2 1)
(-1.0,-1.0)
Main> solve (Q 1 2 0)
(0.0,-2.0)
Main> solve (Q 1 2 2)
(
Program error: pattern match failure: v1618_v1655 (C -1.#IND -1.#IND)
Parece que es un problema después de que se haya aplicado la raíz cuadrada, pero realmente no estoy seguro. Cualquier ayuda para tratar de detectar lo que va mal o cualquier indicación sobre lo que significa este error sería brillante.
Gracias,
Thomas
El Código:
-- A complex number z = (re +im.i) is represented as a pair of Floats
data Complex = C {
re :: Float,
im :: Float
} deriving Eq
-- Display complex numbers in the normal way
instance Show Complex where
show (C r i)
| i == 0 = show r
| r == 0 = show i++"i"
| r < 0 && i < 0 = show r ++ " - "++ show (C 0 (i*(-1)))
| r < 0 && i > 0 = show r ++ " + "++ show (C 0 i)
| r > 0 && i < 0 = show r ++ " - "++ show (C 0 (i*(-1)))
| r > 0 && i > 0 = show r ++ " + "++ show (C 0 i)
-- Define algebraic operations on complex numbers
instance Num Complex where
fromInteger n = C (fromInteger n) 0 -- tech reasons
(C a b) + (C x y) = C (a+x) (b+y)
(C a b) * (C x y) = C (a*x - b*y) (b*x + b*y)
negate (C a b) = C (-a) (-b)
instance Fractional Complex where
fromRational r = C (fromRational r) 0 -- tech reasons
recip (C a b) = C (a/((a^2)+(b^2))) (b/((a^2)+(b^2)))
root :: Complex -> Complex
root (C x y)
| y == 0 && x == 0 = C 0 0
| y == 0 && x > 0 = C (sqrt ( ( x + sqrt ( (x^2) + 0 ) ) / 2 ) ) 0
| otherwise = C (sqrt ( ( x + sqrt ( (x^2) + (y^2) ) ) / 2 ) ) ((y/(2*(sqrt ( ( x + sqrt ( (x^2) + (y^2) ) ) / 2 ) ) ) ) )
-- quadratic polynomial : a.x^2 + b.x + c
data Quad = Q {
aCoeff, bCoeff, cCoeff :: Complex
} deriving Eq
instance Show Quad where
show (Q a b c) = show a ++ "x^2 + " ++ show b ++ "x + " ++ show c
solve :: Quad -> (Complex, Complex)
solve (Q a b c) = ( sol (+), sol (-) )
where sol op = (op (negate b) $ root $ b*b - 4*a*c) / (2 * a)
Solución
Sus números parecen desnormalizados en su error:
(C -1.#IND -1.#IND)
En este caso, no puede asumir que cualquier comparación en flotante ya no sea válida. Esto está en la definición de números de coma flotante. Entonces tu definición de espectáculo
show (C r i)
| i == 0 = show r
| r == 0 = show i++"i"
| r < 0 && i < 0 = show r ++ " - "++ show (C 0 (i*(-1)))
| r < 0 && i > 0 = show r ++ " + "++ show (C 0 i)
| r > 0 && i < 0 = show r ++ " - "++ show (C 0 (i*(-1)))
| r > 0 && i > 0 = show r ++ " + "++ show (C 0 i)
deja la oportunidad para una falla de patrón, debido a números desnormalizados. Puede agregar la siguiente condición
| otherwise = show r ++ "i" ++ show i"
Ahora, por qué es así, cuando evalúas
b * b - 4 * a * c
con Q 1 2 2, obtienes -4, y luego en la raíz, caes en tu último caso, y en la segunda ecuación:
y
-----------------------------
________________
/ _______
/ / 2 2
/ x + \/ x + y
2 * \ / ----------------
\/ 2
-4 + sqrt ((-4) ^ 2) == 0
, a partir de ahí, estás condenado, división por 0, seguido de un " NaN " (no un número), atornillando todo lo demás
Otros consejos
Dave golpeó el clavo en la cabeza.
Con el código original en GHCi, obtengo:
*Main> solve (Q 1 2 2) (*** Exception: c.hs:(11,4)-(17,63): Non-exhaustive patterns in function show
Si actualizamos el bloque show:
instance Show Complex where
show (C r i)
| i == 0 = show r
| r == 0 = show i++"i"
| r < 0 && i < 0 = show r ++ " - "++ show (C 0 (i*(-1)))
| r < 0 && i > 0 = show r ++ " + "++ show (C 0 i)
| r > 0 && i < 0 = show r ++ " - "++ show (C 0 (i*(-1)))
| r > 0 && i > 0 = show r ++ " + "++ show (C 0 i)
| otherwise = "???(" ++ show r ++ " " ++ show i ++ ")"
entonces obtenemos esta información en GHCi:
*Main> :l c.hs [1 of 1] Compiling Main ( c.hs, interpreted ) c.hs:22:0: Warning: No explicit method nor default method for `abs' In the instance declaration for `Num Complex' c.hs:22:0: Warning: No explicit method nor default method for `signum' In the instance declaration for `Num Complex' Ok, modules loaded: Main. *Main> solve (Q 1 2 2) (???(NaN NaN),???(NaN NaN))
Yo nací y crecí en GHCi, así que no sé exactamente cómo se compara Hugs en términos de advertencias y errores; pero parece que GHCi es un claro ganador al decirle qué salió mal.
Fuera de mi cabeza: Podría ser un problema con su definición de show
para Complex
.
Noto que no tiene un caso predeterminado como este:
| otherwise = ...
Por lo tanto, si sus condiciones con r
y i
no son exhaustivas, obtendrá una falla de coincidencia de patrón
.