¡Buenas noches! Ante unas imprecisiones que surgen con el manejo de números muy grandes con el tipo Number, dejo una propuesta para poder soportar estos números y a la vez seguir soportando la representación con punto flotante.
Básicamente consiste en que Number encierre un valor de tipo Either Integer Double, y a la hora de resolver una función devuelva el tipo correspondiente de estos dos. Esto implica que la conversión se hace por cada operación, por lo tanto para que dé el test:
it "no se pierde informacion al redondear en sucesivas operaciones" $ do
(1 / 3 * 3) `shouldBeTheSameNumberAs` 1
Mi solución fue que, al representarlo como Double, se redondee a 10 decimales, pero al chequear si debe ser convertido a Int se redondee a 9. De esta manera:
>>> 1 / 3 * 3
>>> 0,3333333333 * 3 -- este primer resultado no se convierte a Integer, por lo tanto queda representado con 10 decimales
>>> 0,9999999999 -- este resultado sí se convierte a Integer porque, redondeado a 9 decimales, da 1
>>> 1
Surge una limitación al operar un Number que es Integer con un Number que es Double. Para preservar el valor de los decimales, hay que convertir el Integer a Double, lo cual naturalmente hace que se pierda la precisión extra del Integer para números muy grandes (que sólo se mantiene al operar entre Integers y con funciones como show).
Además, agregué un test en la línea 24 para verificar que un número que antes no se podía representar ahora sí puede ser representado.
Aclaración: este test ahora no pasa:
it "los resultados de divisiones se redondean" $ do
(1 / 3) `shouldBeTheSameNumberAs` 0.333333333
Pero es por el cambio que mencioné más arriba. Ahora, la cuenta arroja un decimal más (10 en vez de 9).
¡Buenas noches! Ante unas imprecisiones que surgen con el manejo de números muy grandes con el tipo Number, dejo una propuesta para poder soportar estos números y a la vez seguir soportando la representación con punto flotante. Básicamente consiste en que Number encierre un valor de tipo
Either Integer Double
, y a la hora de resolver una función devuelva el tipo correspondiente de estos dos. Esto implica que la conversión se hace por cada operación, por lo tanto para que dé el test:Mi solución fue que, al representarlo como Double, se redondee a 10 decimales, pero al chequear si debe ser convertido a Int se redondee a 9. De esta manera:
Surge una limitación al operar un Number que es Integer con un Number que es Double. Para preservar el valor de los decimales, hay que convertir el Integer a Double, lo cual naturalmente hace que se pierda la precisión extra del Integer para números muy grandes (que sólo se mantiene al operar entre Integers y con funciones como show). Además, agregué un test en la línea 24 para verificar que un número que antes no se podía representar ahora sí puede ser representado. Aclaración: este test ahora no pasa:
Pero es por el cambio que mencioné más arriba. Ahora, la cuenta arroja un decimal más (10 en vez de 9).