8 votos

¿Por qué es $3 \times 0.3 = 0.8999999999999999$ en coma flotante?

¿Puede alguien ayudarme a explicar este hecho? He intentado leer algunos artículos en la web sobre el punto flotante pero siempre es un tema difícil de entender para mí.

Esto es lo que obtengo de Python 3.3.0

enter image description here

Una explicación breve o media es suficiente. Se agradece mucho. Gracias.

3 votos

Aquí hay un bonito vídeo que explica cómo se producen estos errores de punto flotante. Resumiendo: se debe a los "decimales repetidos" truncados cuando los números se expresan en binario.

3 votos

Los ordenadores tienen que hacer un montón de cosas raras internamente para poder manejar la aritmética de coma flotante, y nunca pueden hacerlo perfectamente (siempre habrá algún error para los decimales no terminados). Las diferencias que ves ahí son el error del producto en los métodos particulares que se utilizan.

6 votos

Enlace obligatorio a stackoverflow: ¿Está rota la matemática de punto flotante?

26voto

Ya Basha Puntos 130

La respuesta sencilla es que el ordenador almacena los números en binario: $0.3$ debería haber sido almacenado como $$0.01001100110011001100\ldots$$ Sin embargo, un ordenador no tiene un espacio de almacenamiento infinito, por lo que tiene que redondearlo a un número determinado de bits. Por lo tanto, no es exactamente $0.3$ que se almacena, pero algo más o menos $10^{-16}$ más pequeño o más grande (según el tipo de flotador que se utilice). Ese error de redondeo es lo que ves en tus cálculos.

Probablemente puedas ver ese error de redondeo más directamente haciendo cálculos como 0.1+0.2-0.3 o 0.1*2-0.2 . Algunos de ellos realmente darán 0 pero muchos de ellos darán respuestas del orden de E-16 o E-17

Tenga en cuenta que esto también es por lo que el uso de == para comparar números de punto flotante es una mala idea. Números que matemáticamente deberían ser iguales podrían ser desiguales dentro del ordenador.

11voto

andy.holmes Puntos 518

Toma algunos dígitos más para captar con mayor precisión cuál es el contenido binario de esos números en coma flotante (aunque sólo sean necesarios 16 dígitos para identificar cada uno de estos números):

>>> print "%.50f" % 0.3
0.29999999999999998889776975374843459576368331909180
>>> print "%.50f" % (2*0.3)
0.59999999999999997779553950749686919152736663818359
>>> print "%.50f" % (3*0.3)
0.89999999999999991118215802998747676610946655273438
>>> print "%.50f" % 0.2
0.20000000000000001110223024625156540423631668090820
>>> print "%.50f" % (3*0.2)
0.60000000000000008881784197001252323389053344726562

Así que ves que no hay un binario 0.2 o 0.3 ya que son fracciones binarias periódicas infinitas.

7voto

Kempo63 Puntos 39

Considere lo que significan los dígitos individuales de un número como 12,34. Su valor es $1\cdot10^1 + 2\cdot10^0 + 3\cdot10^{-1} + 4\cdot10^{-2}$ . Esto es lo que aprendiste en la escuela primaria sobre el "lugar de las unidades" y el "lugar de las decenas", pero escrito en una notación matemática más formal. Los ordenadores manejan los números en coma flotante de la misma manera, sólo que son mucho mejores en base 2 que en base 10, así que hacen exactamente el mismo proceso en binario. 5,25 se divide en $1\cdot2^1 + 0\cdot2^1 + 1*\cdot2^0 + 0\cdot2^{-1} + 1\cdot2^{-2}$ . Si lo reescribiera en la forma decimal normal, pero utilizando valores de base 2 en lugar de base 10, $5.25_{10}$ se escribiría como $101.01_2$ (La base se anota aquí con un subíndice, que es una notación muy común cuando se trabaja con diferentes bases. Ayuda a mantener los números en orden). Así es como los ordenadores suelen abordar los números en coma flotante.

Si te pregunto cuánto es 1/3 como decimal, dirías algo así como $0.33333..._{10}$ Sin embargo, si siguieras escribiendo 3's, te quedarías sin espacio, así que probablemente dirías "está cerca de $0.33333_{10}$ ." Los ordenadores hacen lo mismo. Mientras que 1/2 en base2 es $0.1_2$ y 1/8 es $0.001_2$ en base 2, no todos los números funcionan tan limpiamente. En particular, 3/10 ( $0.3_{10}$ en decimal) es igual a $0.010011001100..._2$ que debe ser redondeado. Son estos errores de redondeo los que causan los efectos inusuales que se ven.

Como regla general, nunca se debe confiar en la equivalencia exacta con == para determinar si dos números en coma flotante son iguales, debido a estos errores de redondeo. Uno siempre los compara con alguna tolerancia.

Muchas CPUs tienen un modo "decimal" para sus números en coma flotante que utilizan la base 10 en lugar de la base 2. Esto puede ser más lento, o de menor precisión, pero es una solución popular en situaciones como la banca, donde el manejo exacto de fracciones de un centavo tiene que coincidir exactamente. Dado que es natural que vigilemos los errores de redondeo en decimales, esto hace que los números se comporten de forma más intuitiva. Sin embargo, en general esto se ha dejado de lado. Casi todo el mundo utiliza la representación binaria normal IEE-754 de los números en coma flotante, porque es un formato muy bien redondeado. Los que necesitan exactitud suelen utilizar en su lugar la matemática de punto fijo, que garantiza resultados exactos utilizando la aritmética de enteros.

1voto

user322675 Puntos 11

La aritmética binaria de punto flotante sólo puede representar exactamente fracciones con una potencia de $2$ como denominador.

$0.3$ no es una fracción de este tipo, por lo que se representa con un número que se desvía como máximo la mitad de la unidad más pequeña del número en coma flotante. Si se multiplica por $3$ El resultado puede ser tan erróneo como $0.5$ de la unidad más pequeña para $0.3$ antes de redondear, y de $0.75$ de la unidad más pequeña para $0.9$ tras el redondeo. Lo que significa que puede no ser el mismo que el ordenador elegiría para $0.9$ cuando se le pregunta directamente (ya que entonces trataría de estar fuera como máximo por $0.5$ ).

Y eso para una FPU que tenga los mínimos errores posibles.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X