Präzises Rechnen

xkris

Mitglied
Hallo,

ich bastel jetzt schon seit Tagen an einem Algorithmus der analytisch die Nullstellen eines Polynoms 4.Ordnung bestimmen soll. Leider finde ich immer wieder Eingangsparameter, bei denen der Algorithmus versagt. Genauer gesagt, ist es glaub ich die begrenzte Rechengenauigkeit von c++ denn im Matlab funktioniert der Algoritmus problemlos, was seltsam ist, denn ich benutze für mein C++ Programm long double während matlab nur mit double rechen kann.
Was mir auch Rätsel aufgibt ist folgendes Beispiel:
Code:
cout<<-B/(4*A)<<"+"<<s*W/2<<endl;
L=-B/(4*A)+s*W/2;

Als text ausgabe erhalte ich:
HTML:
-110632887428297.89+110632887428337.91
40.006141662597656

Eigentlich sollte dort 40.02 rauskommen :suspekt:

Meine Frage ist: was macht c++ intern mit den Zahlen und was kommt zur Anzeige denn hier gibt es eine eindeutige Diskrepanz die ich nicht verstehe.
Alle beteiligten Variablen sind long double und die die anzuzeigenden dezimalstellen wurden von mir vorsichtshalber mit setprecision(30) so eingestellt, dass er mir sämtliche Stellen anzeigen sollte.
Achja, das Ergebnis sollte eigentlich 40 sein, mit 40.006 liefert c++ einen sehr ungenauen Wert.
Wäre äußerst nett, wenn mir jemand weiterhelfen könnte oder eine Idee hat, ich verzweifel langsam an diesem Problem.
Also, besten Dank im Voraus

Gruß
Kristian
 
Hm.
Probleme mit double-Genauigkeit hatte ich auch schon.
Wenn du wirklich präzise Berechnungen haben willst, dann musst du dich vielleicht nach einer Mathe-Bibliothek umschauen.

Bzw. Bei so ner krassen Abweichung.... Hast du deinen Algorithmus schon überprüft?
Also, ich kann nicht so viel folgern aus dem Code-Abschnitt von dir...


denn ich benutze für mein C++ Programm long double während matlab nur mit double rechen kann

Übrigens, ob long double oder double macht meistens keinen Unterschied, weil es meistens dasselbe ist, je nach Implementation.
Kannst du feststellen, ob das bei dir auch so ist. Mit sizeof() und dann die Größen von long double und double vergleichen.


die anzuzeigenden dezimalstellen wurden von mir vorsichtshalber mit setprecision(30) so eingestellt, dass er mir sämtliche Stellen anzeigen sollte.

Hehe, in dem Moment, wo du das machst, kannst du davon ausgehen, ungenaue Ergebnisse zu erzielen. Jedenfalls bei mir ist das so. Double-Berechnungen sind nur auf den vorderen paar Stellen genau.
Jedenfalls habe ich mal sowas ähnliches gemacht, wie
Code:
double a = 1.7;
a += 1;
cout.setprecision(30);
cout << a << endl;

und es hat mir dann schon einen ungenauen Wert ausgespuckt. Halt erst nach 10 Dezimalen oder so. (Bzw, ich weiß nicht mehr ganz genau, wie der code war. Aber etwa so simpel.)
 
Hallo Beichtpfarrer,

vielen Dank erstmal für deine Antwort.

Das Problem welches zu den Ungenauigkeiten führt sind Rechnungen wie diese:

-4.4942605213487257e057 + 4.4942605213487257e057

sollte eigentlich null sein, aber c++ scheint das intern anders zu berechen, denn das Ergebnis dieser Addition ist eben nicht 0 sondern laut c++ :

4.2535295865117308e037

durch Wechsel von double zu long double hab ich mein Endergebnis immerhin um eine Nachkommastelle verbessern können. Der erweiterte Zahlenbereich von long double scheint hier keine Rolle zu spielen, eher die erhöhte Stellengenauigkeit, die liegt nämlich bei 15 Stellen für double und bei 19 Stellen für long double.Bei Rechnungen wie im obigen Beispiel macht das halt immer noch einiges aus, wenn die Zahl nach 19 Stellen ungenau ist.
setprecicion() hat keinen Einfluss weil hiermit lediglich die Anzahl der angezeigten Dezimalstellen eingestellt wird.
Mir ist auch schon aufgefallen, dass wenn ich c++ ein double wie 12.0 übergebe, dass das dann später irgendwo als 12.000000000001 oder so auftaucht. Keine Ahnung warum, bin da ziemlich ratlos

Gruß
Kristian
 
Das hat mit C++ gar nix zu tuen, sondern mit dem double-format.

double ist ein ungenaues Format das aufgrund seines Aufbaus bestimmte Zahlen nicht Darstellen kann, und statt dessen immer den nächst größeren/kleineren wert annimmt. (Dein Beispiel mit 12.00 ist so eins, das wird dann zu 12.000000000001)

Hier steht mehr darüber: http://de.wikipedia.org/wiki/Gleitkommazahl

(Stichwort: approximative Darstellung einer reellen Zahl, also annähernd, nicht präzise)

Wenn Du mit hoher Genauigkeit rechnen willst ist double der falsche Datentyp und wie andere schon sagten brauchst Du dafür entsprechende Mathe-Bibliotheken.
 
Ein Problem könnte die Auslöschung sein. Wird auch auf der Wikipedia-Seite zu Gleitkommazahlen beschrieben.
 
Zurück