Existen dos dificultades comunes cuando se trabaja con aritmética de coma flotante.
El primer problema es que los puntos flotantes de Ruby tienen una precisión fija. En la práctica, esto será 1) ningún problema para usted o 2) desastroso, o 3) algo intermedio. Considere lo siguiente:
# float
1.0e+25 - 9999999999999999900000000.0
#=> 0.0
# bigdecimal
BigDecimal("1.0e+25") - BigDecimal("9999999999999999900000000.0")
#=> 100000000
¡Una diferencia de precisión de 100 millones! Muy serio, ¿verdad?
Excepto que el error de precisión es solo aproximadamente 0.000000000000001% del número original. Realmente depende de usted decidir si esto es un problema o no. Pero el problema se elimina usando BigDecimal
porque tiene una precisión arbitraria. Tu único límite es la memoria disponible para Ruby.
El segundo problema es que los puntos flotantes no pueden expresar todas las fracciones con precisión. En particular, tienen problemas con fracciones decimales, porque los flotantes en Ruby (y en la mayoría de los demás idiomas) son puntos flotantes binarios. Por ejemplo, la fracción decimal 0.2
es una fracción binaria eternamente repetitiva (0.001100110011...
). Esto nunca se puede almacenar con precisión en un punto flotante binario, sin importar cuál sea la precisión.
Esto puede marcar una gran diferencia cuando se redondean los números. Considerar:
# float
(0.29 * 50).round
#=> 14 # not correct
# bigdecimal
(BigDecimal("0.29") * 50).round
#=> 15 # correct
A BigDecimal
puede describir decimales fracciones con precisión. Sin embargo, hay fracciones que tampoco se pueden describir con precisión con una fracción decimal. Por ejemplo, 1/9
es una fracción decimal eternamente repetitiva (0.1111111111111...
).
De nuevo, esto te morderá cuando redondeas un número. Considere:
# bigdecimal
(BigDecimal("1")/9 * 9/2).round
#=> 0 # not correct
En este caso, el uso de puntos flotantes decimal todavía dar un error de redondeo.
Algunas conclusiones:
- flotadores decimales son impresionantes si lo hace cálculos con fracciones decimales (dinero, por ejemplo).
- Ruby's
BigDecimal
también funciona bien si necesita puntos flotantes de precisión arbitrarios, y realmente no le importa si son puntos flotantes decimales o binarios.
- Si trabajas con datos (científicos), normalmente trabajas con números de precisión fijos; Los flotadores integrados de Ruby probablemente sean suficientes.
- Nunca se puede esperar la aritmética con cualquier tipo de punto flotante para ser precisos en todas las situaciones.
"En la práctica, esto será 1) no hay problema para ti o 2) desastroso, o 3) algo intermedio" - me encanta cómo lo has reducido :) –