10Pines / pdepreludat

BSD 3-Clause "New" or "Revised" License
24 stars 2 forks source link

Solución para issue #39 #53

Closed T-J-Antonio closed 1 year ago

T-J-Antonio commented 1 year ago

¡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).