2010-05-07 11 views
7

lo siento si es tonto, pero no pudo encontrar una respuesta.C++ error de truncamiento numérico

#include <iostream> 

using namespace std; 

int main() 
{ 
double a(0); 
double b(0.001); 
cout << a - 0.0 << endl; 
for (;a<1.0;a+=b); 
cout << a - 1.0 << endl; 
for (;a<10.0;a+=b); 
cout << a - 10.0 << endl; 
cout << a - 10.0-b << endl; 
return 0; 
} 

de salida:
6.66134e-16
0,001
-1.03583e-13

Probamos la compilación con MSVC9, MSVC10, Borland C++ 2010. Todos ellos llegar en el finaliza el error de aproximadamente 1e-13. ¿Es normal tener una acumulación de error tan importante en solo 1000, 10000 incrementos?

+3

http://docs.sun.com/source/806-3568/ncg_goldberg.html – Anycorn

+0

http://home.comcast.net/~tom_forsyth/blog. wiki.html # [[A% 20matter% 20of% 20precision]] (no yo, heh) –

Respuesta

13

Sí, esto es un error de punto flotante de representación numérica normal. Tiene que ver con el hecho de que el hardware debe aproximarse a la mayoría de los números de punto flotante, en lugar de almacenarlos exactamente. Por lo tanto, el compilador que use no debería importar.

What Every Computer Scientist Should Know About Floating-Point Arithmetic

+0

Gracias, entiendo el error de truncamiento y todas las otras porquerías. Hice un montón de trabajo teórico sobre métodos numéricos, pero nunca lo comprobé y quedé muy sorprendido de descubrir qué tan grande es ... – Andrew

+1

Bueno, un doble te da aproximadamente 16 dígitos decimales de precisión, eso está bien. Cuando haces 1000 vueltas, tienes 13 dígitos de precisión. – WhirlWind

+1

Ten en cuenta que es particularmente doloroso solo con números irracionales (en la base 2). Si usas poderes de dos, estarás bien. P.ej. si su sumador fue 0.5, 0.25, 0.125, 0.0625, etc., eventualmente agregarán * exactamente * a 1.0, ya que estos valores en la base 2 son 0.1, 0.01, 0.001 y 0.0001. –

1

Este es el problema con números de punto flotante — son aproximados, y ocurren cosas extrañas en cero (es decir, aparecen representaciones extrañas). Debido a esto, algunas de las operaciones en números que da por sentados deben manejarse con mayor delicadeza.

Al comparar dos números, no se puede simplemente decir a == b porque uno puede ser 0 y el otro -1.03583e-13 debido a la pérdida de precisión a lo largo de las operaciones de punto flotante aplicado para llegar a a y b. Debe elegir una tolerancia arbitraria, como esta: fabs(a,b) < 1e-8.

Al imprimir un número, a menudo necesita limitar el número de dígitos impresos. Si usa printf, puede decir printf("%g\n", a);, que no imprimirá cosas como -1.03583e-13. No sé si hay un iostream análogo a %g; ¿esta ahí?

2

Esta es la razón por al usar un error de punto flotante que nunca debe hacer:

if(foo == 0.0){ 
    //code here 
} 

y en lugar de hacer

bool checkFloat(float _input, float _compare, float _epsilon){ 
    return (_input + _epsilon > _compare) && (_input - _epsilon < _compare); 
} 
+1

Comprobar en contra de cero está bien en muchas circunstancias, ya que puede representarse exactamente en el hardware, pero, por supuesto, depende de lo que esté haciendo con él ... Comenzar en 1 y restar .1 diez veces no conducirá a 0, por supuesto. –

+1

Eso es muy cierto, pero en la mayoría de los casos no es una buena práctica. Me gusta equivocarme por el lado de la precaución. – wheaties

+0

error en el lado de la precaución ... gracioso;) O tal vez errar bajo el tamaño de épsilon. – WhirlWind

2

pensar en esto. cada operación introduce un ligero error, pero la siguiente operación usa un resultado levemente defectuoso. si se le dan suficientes iteraciones, se desviará del resultado verdadero. si lo desea, escriba sus expresiones en el formulario t0 = (t + y + e), t1 = (t0 + y +e) y descubra los términos con épsilon. de sus términos puede estimar el error aproximado.

también hay una segunda fuente de error: en algún momento se combinan números relativamente pequeños y relativamente grandes, hacia el final. si recuerda la definición de precisión de máquina, 1 + e = 1, en algún momento las operaciones perderán bits significativos.

Esperemos que esto ayuda a aclarar en términos profanos

Cuestiones relacionadas