Pregunta

¿Por qué este código? 7.30 - 7.20 en rubí regresa 0.0999999999999996, no 0.10?

Pero si escribo 7.30 - 7.16, por ejemplo, todo estará bien, lo conseguiré 0.14.

¿Cuál es el problema y cómo puedo solucionarlo?

Otros consejos

El problema es que algunos números podemos escribir fácilmente en decimal no tienen una representación exacta en el formato de punto flotante en particular implementado por hardware actual. Una manera informal de decir esto es que todos los números enteros hacen, pero no todas las fracciones, ya que normalmente almacenamos la fracción con un exponente 2**e. Por lo tanto, usted tiene 3 opciones:

  1. Para rematar adecuadamente. El resultado no redondeada es siempre muy, muy de cerca, por lo que un resultado redondeado es invariablemente "perfecta". Esto es lo que Javascript y mucha gente ni siquiera se da cuenta de que JS hace todo en coma flotante.

  2. Utilice la aritmética de punto fijo. Rubí en realidad lo hace muy fácil; que es uno de los únicos idiomas que se desplaza a la perfección clase Bignum de Fixnum como números se hacen más grandes.

  3. Utilice una clase que está diseñado para resolver este problema, al igual que BigDecimal

Para estudiar el problema con más detalle, podemos tratar de representar a su "7.3" en binario. La parte 7 es fácil, 111, pero ¿cómo hacer 0.3? 111.1 es de 7.5, demasiado grande, es decir 111.01 7.25, cada vez más cerca. Resulta que, 111.010011 es la "más cercana siguiente número más pequeño", 7,296875, y cuando tratamos de rellenar el 0,003125 falta el tiempo nos damos cuenta de que es sólo 111,010011001100110011 ... para siempre, no representable en nuestra codificación elegida en una cadena de bits finita .

El problema es que de punto flotante es inexacta . Se puede resolver mediante el uso de números enteros racionales, BigDecimal o simplemente (por ejemplo, si desea almacenar el dinero que puede almacenar el número de centavos como un int en lugar de la cantidad de dólares como un float).

BigDecimal puede almacenar con precisión cualquier número que tiene un número finito de dígitos en la base 10 y rondas de números que no lo hacen (por lo que tres tercios no son un todo).

racional puede almacenar con precisión cualquier número racional y no puede almacenar los números irracionales en absoluto.

Esto es un error común de cómo los números de punto de flotación están representados en la memoria.

Uso BigDecimal si necesita resultados exactos.

result=BigDecimal.new("7.3")-BigDecimal("7.2")
puts "%2.2f" % result

Es interesante notar que un número que tiene unas décimas en una base puede típicamente tener un gran número de decimales en otra. Por ejemplo, se necesita un número infinito de decimales para expresar 1/3 (= 0,3333 ...) en la base 10, pero sólo uno decimal en la base 3. De manera similar, se necesitan muchos decimales para expresar el número 1/10 ( = 0,1) en la base 2.

Desde que está haciendo cálculos de coma flotante a continuación, el número devuelto es la que utiliza el equipo de precisión.

Si desea una respuesta más cerca, con una precisión conjunto, simplemente múltiple por el flotador que (como en 100), convertirlo a un int, hacer los cálculos, y se divide.

Hay otras soluciones, pero me parece que este es el más simple ya que el redondeo siempre parece un poco dudoso para mí.

Esto se ha hecho antes aquí, puede que desee buscar algunas de las respuestas dadas antes, como este: Tratar con problemas de precisión en números de punto flotante

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top