¿Por qué veo una variable doble inicializada a algún valor como 21.4 como 21.399999618530273?


double r = 11.631;
double theta = 21.4;

En el depurador, estos se muestran como 11.631000000000000 y 21.399999618530273.

¿Cómo puedo evitar esto?

Author: yesraaj, 2008-10-07

14 answers

Estos problemas de precisión se deben a la representación interna de números de coma flotante y no hay mucho que pueda hacer para evitarlo.

Por cierto, imprimir estos valores en tiempo de ejecución a menudo todavía conduce a los resultados correctos, al menos utilizando compiladores modernos de C++. Para la mayoría de las operaciones, esto no es un gran problema.

 55
Author: Konrad Rudolph,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-07 07:42:32

Me gustó La explicación de Joel , que trata sobre un problema de precisión de punto flotante binario similar en Excel 2007:

Ver cómo hay un montón de 0110 0110 0110 allí al final? Eso es porque 0.1 no tiene ninguna representación exacta en binario... es un número binario repetido. Es como cómo 1/3 no tiene representación en decimal. 1/3 es 0.33333333 y tienes que seguir escribiendo 3 para siempre. Si pierdes la paciencia, obtienes algo inexacto.

Así que puedes imaginar cómo, en decimal, si intentaras hacer 3*1/3, y no tuvieras tiempo para escribir 3 para siempre, el resultado que obtendrías sería 0.99999999, no 1, y la gente se enojaría contigo por estar equivocada.

 37
Author: Jeff Atwood,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-02-22 14:09:19

Si tienes un valor como:

double theta = 21.4;

Y quieres hacer:

if (theta == 21.4)
{
}

Tienes que ser un poco inteligente, tendrás que comprobar si el valor de theta es realmente cercano a 21.4, pero no necesariamente ese valor.

if (fabs(theta - 21.4) <= 1e-6)
{
}
 10
Author: Mark Ingram,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-01-04 19:14:15

Esto es en parte específico de la plataforma, y no sabemos qué plataforma está utilizando.

También es en parte un caso de saber lo que realmente quiere ver. El depurador le muestra - hasta cierto punto, de todos modos-el valor preciso almacenado en su variable. En mi artículo sobre números binarios en coma flotante en.NET, hay una clase C# que le permite ver el número absolutamente exacto almacenado en un doble. La versión en línea no está funcionando en este momento - trate de poner uno en otro sitio.

Dado que el depurador ve el valor "real", tiene que hacer una llamada de juicio sobre qué mostrar - podría mostrar el valor redondeado a unos pocos decimales, o un valor más preciso. Algunos depuradores hacen un mejor trabajo que otros leyendo las mentes de los desarrolladores, pero es un problema fundamental con los números binarios de coma flotante.

 7
Author: Jon Skeet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-07 09:35:14

Utilice el tipo de punto fijo decimal si desea estabilidad en los límites de precisión. Hay gastos generales, y debe convertir explícitamente si desea convertir a coma flotante. Si lo hace convertir a punto flotante volverá a introducir las inestabilidades que parecen molestarle.

Alternativamente puedes superarlo y aprender a trabajar con la precisión limitada de la aritmética de coma flotante. Por ejemplo, puede usar el redondeo para hacer que los valores converjan, o puede usar epsilon comparaciones para describir una tolerancia. "Epsilon" es una constante que define la tolerancia. Por ejemplo, puede optar por considerar que dos valores son iguales si están dentro de 0.0001 el uno del otro.

Se me ocurre que podría usar la sobrecarga del operador para hacer las comparaciones de epsilon transparentes. Eso sería genial.


Para las representaciones de exponentes de mantissa, EPSILON debe calcularse para permanecer dentro de la precisión representable. Para un número N, Epsilon = N / 10E + 14

System.Double.Epsilon es el valor positivo representable más pequeño para el tipo Double. Es demasiado pequeño para nuestro propósito. Lea Los consejos de Microsoft sobre las pruebas de igualdad

 5
Author: Peter Wone,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-08 23:36:47

Me he encontrado con esto antes ( en mi blog) - Creo que la sorpresa tiende a ser que los números 'irracionales' son diferentes.

Por 'irracional' aquí solo me refiero al hecho de que no se pueden representar con precisión en este formato. Los números irracionales reales (como π - pi) no se pueden representar con precisión en absoluto.

La mayoría de la gente está familiarizada con que 1/3 no funciona en decimal: 0.33333333333333...

Lo extraño es que 1.1 no funciona en flotadores. Personas espere que los valores decimales funcionen en números de coma flotante debido a cómo piensan de ellos:

1.1 es 11 x 10^-1

Cuando en realidad están en base-2

1.1 es 154811237190861 x 2^-47

No puedes evitarlo, solo tienes que acostumbrarte al hecho de que algunos flotadores son 'irracionales', de la misma manera que 1/3 lo es.

 4
Author: Keith,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-10 15:59:14

Una forma de evitar esto es usar una biblioteca que use un método alternativo de representar números decimales, como BCD

 3
Author: Shane MacLaughlin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-07 07:52:18

Me parece que 21.399999618530273 es la representación de precisión simple (flotante) de 21.4. Parece que el depurador está lanzando hacia abajo desde double para flotar en algún lugar.

 3
Author: MikeJ-UK,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-07 09:41:06

Si está utilizando Java y necesita precisión, utilice la clase BigDecimal para los cálculos en coma flotante. Es más lento pero más seguro.

 2
Author: Shimi Bandiel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-07 07:57:29

No puede evitar esto ya que está utilizando números de coma flotante con una cantidad fija de bytes. Simplemente no hay isomorfismo posible entre los números reales y su notación limitada.

Pero la mayoría de las veces simplemente puedes ignorarlo. 21.4 = = 21.4 seguiría siendo cierto porque sigue siendo los mismos números con el mismo error. Pero 21.4 f = = 21.4 puede no ser cierto porque el error para float y double son diferentes.

Si necesita precisión fija, tal vez debería probar el punto fijo numero. O incluso enteros. Yo, por ejemplo, uso a menudo int (1000 * x) para pasar al buscapersonas de depuración.

 2
Author: akalenuk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-07 10:50:27
 2
Author: Chobicus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-02 14:21:30

Si le molesta, puede personalizar la forma en que se muestran algunos valores durante la depuración. Úselo con cuidado: -)

Mejora de la depuración con los atributos de visualización del Depurador

 1
Author: Larry,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-07 09:47:43

Se refiere a Aritmética Decimal General

También tome nota al comparar flotadores, vea esta respuesta para más información.

 0
Author: grom,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:34:54

Según el javadoc

" Si al menos uno de los operandos a un operador numérico es de tipo double, entonces el
la operación se lleva a cabo utilizando aritmética de coma flotante de 64 bits, y el resultado de la
operador numérico es un valor de tipo doble. Si el otro operando no es un doble, es
primero ampliado (§5.1.5) para escribir doble por promoción numérica (§5.6)."

Aquí está la Fuente

 0
Author: MaheshVarma,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-21 09:30:08