2010-05-07 10 views
7

Entschuldigung wenn dumm aber konnte keine Antwort finden.C++ Numerischer Trunkierungsfehler

#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; 
} 

Ausgang:
6.66134e-16
0,001
-1.03583e-13

Versuchte es mit MSVC9, MSVC10, Borland C++ 2010 alle von ihnen in die ankommen Kompilieren end auf den Fehler von etwa 1e-13. Ist es normal, eine solch signifikante Fehlerakkumulation über nur 1000, 10000 Inkremente zu haben?

+3

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

+0

http://home.comcast.net/~tom_forsyth/blog zu klären. wiki.html # [[A% 20matter% 20of% 20precision]] (nicht ich, heh) –

Antwort

13

Ja, das ist der normale numerische Gleitkommafehler. Es hat damit zu tun, dass die Hardware die meisten Fließkommazahlen approximieren muss, anstatt sie genau zu speichern. Daher sollte der verwendete Compiler keine Rolle spielen.

What Every Computer Scientist Should Know About Floating-Point Arithmetic

+0

Danke, ich verstehe Trunkierungsfehler und all den anderen Mist. Ich habe eine Menge theoretischer Arbeit über numerische Methoden gemacht, aber ich habe es nie selbst überprüft und war sehr überrascht herauszufinden, wie groß es ist ... – Andrew

+1

Nun, ein Doppel gibt Ihnen etwa 16 Dezimalstellen Genauigkeit, das ist in etwa richtig. Wenn Sie eine 1000-fache Schleife durchführen, sind Sie auf etwa 13 Stellen genau. – WhirlWind

+1

Beachten Sie, dass es nur mit irrationalen (in Basis 2) Zahlen besonders schmerzhaft ist. Wenn Sie Zweierpotenzen verwenden, geht es Ihnen gut. Z.B. Wenn Ihr Addierer 0,5, 0,25, 0,125, 0,0625 usw. ist, addieren sie schließlich * genau * zu 1,0, da diese Werte in Basis 2 0,1, 0,01, 0,001 und 0,0001 sind. –

1

Das ist das Problem mit Gleitkommazahlen — sie sind ungefähr, und seltsame Dinge geschehen auf Null (das heißt, seltsame Darstellungen erscheinen). Aus diesem Grund müssen einige der Operationen auf Zahlen, die Sie als selbstverständlich betrachten, delikater gehandhabt werden.

Wenn zwei Zahlen zu vergleichen, man kann nicht einfach a == b sagen, weil man 0 sein könnte und die anderen -1.03583e-13 durch den Verlust von Genauigkeit entlang der Gleitkomma-Operationen angewandt a und b zu bekommen. Sie müssen eine beliebige Toleranz wie folgt wählen: fabs(a,b) < 1e-8.

Beim Drucken einer Nummer müssen Sie häufig die Anzahl der gedruckten Ziffern begrenzen. Wenn Sie printf verwenden, können Sie printf("%g\n", a); sagen, die Dinge wie -1.03583e-13 nicht drucken wird. Ich weiß nicht, ob es eine iostream Analog zu %g gibt; ist da? Diese

2

ist, warum, wenn eine Gleitkomma-Fehler verwenden, sollten Sie nie tun:

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

und stattdessen tun

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

Die Überprüfung gegen Null ist in vielen Fällen in Ordnung, wie es in der Hardware genau dargestellt werden kann, aber natürlich hängt es davon ab, was Sie damit tun ... Beginnen bei 1 und Subtrahieren 0,1 zehnmal wird nicht zu 0 führen, Na sicher. –

+1

Das ist sehr wahr, aber in den meisten Fällen ist es einfach nicht gut. Ich mag Fehler auf der Seite der Vorsicht. – wheaties

+0

irren auf der Seite der Vorsicht ... lustig;) Oder vielleicht irren unter der Größe von Epsilon. – WhirlWind

2
über diese

denken. Jede Operation führt zu einem kleinen Fehler, aber die nächste Operation verwendet ein leicht fehlerhaftes Ergebnis. Bei genügend Wiederholungen weichen Sie vom wahren Ergebnis ab. Wenn Sie möchten, schreiben Sie Ihre Ausdrücke in das Formular t0 = (t + y + e), t1 = (t0 + y +e) und finden Sie Begriffe mit Epsilon. von ihren Bedingungen können Sie ungefähren Fehler schätzen.

gibt es auch eine zweite Fehlerquelle: irgendwann kombinieren Sie relativ kleine und relativ große Zahlen, gegen Ende. Wenn Sie sich an die Definition der Maschinengenauigkeit erinnern, 1 + e = 1, werden die Operationen irgendwann signifikante Bits verlieren.

Hoffentlich hilft diese Begriffe in Laien

Verwandte Themen