Entwickler-Ecke
Delphi Language (Object-Pascal) / CLX - Ungenauigkeit bei Rechnungen
monty.ms - So 15.05.05 15:44
Titel: Ungenauigkeit bei Rechnungen
hallo
ich hab mal eine kleine frage zu diesem Code:
Delphi-Quelltext
1: 2: 3: 4: 5: 6:
| var x1,x2:real; begin x1:=0.2; x2:=x1-0.2; label1.Caption:=floattostr(x2); end; |
.. der ist ja eigentlich richtig, doch warum kommt als Ergebnis nicht 0 raus, sondern 1,1099519E-17 ??
ist das ein fehler von delphi?
ps: sry wenn es hier schonmal war und nochmals sry wenn das der falsche Bereich ist =)
Moderiert von
raziel: Code- durch Delphi-Tags ersetzt.
Moderiert von
raziel: Topic aus Sonstiges verschoben am So 15.05.2005 um 16:00
Fabian W. - So 15.05.05 16:01
Das Problem hatte ich auch mal, aber nur in kleinen Bereichen 0.1-0.1, aber da kam auch immer schrott raus.
delfiphan - So 15.05.05 16:04
Benütze statt
real extended.
Das ist übrigens kein Fehler von Delphi; das wird über die Hardware gerechnet. Die Zahl die du erhältst ist unterhalb der Maschinengenauigkeit. Ich nehm mal die Ungenauigkeit kommt vom Runden oder sowas.
Die Zahl 0.2 lautet im Binärsystem 0.001100110011... (periodisch).
Je nach dem bei welchem Schritt der Berechnung genau gerundet wird, kommt's halt anders raus.
Fabian W.: Was denn für "Schrott"? Die Abweichung ist doch minim.
Fabian W. - So 15.05.05 16:20
Und was ist bei extended jetzt anders?
delfiphan - So 15.05.05 16:29
Extended ist noch ein bisschen genauer als Double-Precision (real).
Fabian W. - So 15.05.05 16:32
rechnet aber auch per Maschiene? Dann kann ich gleich runden wenn real schon
ist...
delfiphan - So 15.05.05 16:41
Fabian W. hat folgendes geschrieben: |
rechnet aber auch per Maschiene? Dann kann ich gleich runden wenn real schon ist... |
Ja, auch Extended geht über die FPU. Der Unterschied zu Double ist, dass bei Extended alle Zahlen vor der Berechnung in den FPU Stack geladen werden
müssen, bevor eine Berechnung stattfinden kann. So ist die ganze Sache symmetrisch und es wird immer beim gleichen Schritt gerundet. Bei Double ist dies nicht unbedingt notwendig und somit geschieht dort die Rundung nicht immer symmetrisch.
Könnte mich aber täuschen, bin kein FPU Experte.
Zur zweiten Bemerkung: Ich sagte, die Abweichung zum korrekten Resultat ist minim. Wenn du die Zahl richtig formatiert darstellst (siehe z.B.
floattostrf) dann sieht man den kleinen Fehler auch nicht. Aber gegen die Tatsache, dass der Rechner nicht exakt rechnen kann, kannst du nichts tun.
Fabian W. - So 15.05.05 16:57
Wie macht das dann der taschenrechner?
delfiphan - So 15.05.05 17:02
Dein Taschenrechner rechnet entweder Dezimal oder rundet beim Anzeigen der Zahlen die letzten 3 Stellen weg (oder keines der beiden).
So, das waren jetzt bald genug deiner Fast-Off-Topic Fragen, findeste nicht auch? Im Prinzip geht es hier ja um
monty.ms. Wenn du dich so sehr für die Sache interessierst, schau mal im Google unter "Floating Point Arithmetic IEEE".
Fabian W. - So 15.05.05 17:10
Also, gut. Die Frage war ja geklärt.
juppinger - Di 03.05.11 12:15
Hallo zusammen,
prima dass ich den gleichen Fehler in meinem Programm entdeckt habe bzw. darauf hingewiesen wurde und in diesem Forum sofort etwas gefunden habe :)
Aber jetzt kommt's:
Ich habe eine Version des Programms erstellt, in der ich von REAL auf EXTENDET umgestellt habe. - Mehr habe ich wirklich nicht gemacht, ausser den Datentyp geändert.
Tests auf diversen (neueren) PCs mit untersch. Windows-Versionen klappt ( Fehler behoben, Programm rechnet genau ).
Jetzt habe ich das Programm auf einem älteren PC laufen lassen (Win XP), und da tritt der Fehler noch immer auf - obwohl der Zahlentyp umgestellt wurde.
Hat da jemand einen Ansatz?
Danke im Vorfeld,
jup
jaenicke - Di 03.05.11 12:34
Es ist doch genau. Die Ungenauigkeit merkst du ja nicht, weil die so weit hinter dem Komma durch die interne Darstellung entsteht.
Zur Ausgabe musst du natürlich darauf achten, dass du das dann richtig ausgibst. Stichwort RoundTo oder Format oder... ;-)
Gammatester - Di 03.05.11 13:46
Und was soll das erklären? Hier wird doch gar nicht auf Gleichheit getestet und es treten
keine Rechenfehler auf! Das Ausgangsproblem
scheint paradox, weil mit unterschiedlichen Genauigkeiten gerechnet wird und 0.2 halt weder real noch extended exakt darstellbar ist. Das Problem tritt nicht auf zB für 0.125 oder 0.25.
Beispiel mit Dezimalsystem. "Real" = 5 Stellen, "Extended" = 8 Stellen, Rechnung wird "Extended" gemacht:
Quelltext
1: 2: 3:
| x1,x2: real; x1 := 0.33333333; // x1 = 0.333333 x2 := x1 - 0.33333333; // x2 = 0.333333 - 0.33333333 = -0.00000333 |
Delete - Di 03.05.11 14:15
Es ist doch egal, ob auf Gleichheit getestet wird oder nicht. Lies den Artikel. Da erkläre ich, warum sich manche Dezimalzahlen nicht ein zu eins im Binärsystem abbilden lassen. Und genau das ist das Problem, warum x1:=0.2; x2:=x1-0.2; eben nicht null ergibt.
Gammatester - Di 03.05.11 14:33
Luckie hat folgendes geschrieben : |
Es ist doch egal, ob auf Gleichheit getestet wird oder nicht. Lies den Artikel. Da erkläre ich, warum sich manche Dezimalzahlen nicht ein zu eins im Binärsystem abbilden lassen. Und genau das ist das Problem, warum x1:=0.2; x2:=x1-0.2; eben nicht null ergibt. |
Unsinn! Wie ja schon festgestellt wurde, ist es exakt gleich 0, wenn extended gerechnet wird. Darüber hinaus sind
alle Gleitkommadifferenzen x-y
exakt, wenn x und y Gleitkommazahlen mit y/2 <= x <= 2*y sind (wenn kein Underflow auftritt). Wenn Du das nicht weißt oder nicht glaubst, suche doch einfach mal nach "Sterbenz Lemma" (Dies ist zB Theorem 11 in D. Goldbergs "What Every Computer Scientist Should Know About Floating-Point Arithmetic", zB via
http://cr.yp.to/2005-590/goldberg.pdf)
KleinesPferd - Di 03.05.11 14:37
Es ist eine Eigenschaft von Fließkommazahlen (float), dass sie generell Näherungswerte der uns gebräuchlichen Zahlen sind.
Eine FLOAT besteht aus einem VorzeichenBit, gefolgt von einer Mantisse (oder Basis) und einem Exponenten.
1. Problem: Null-Darstellung
Mathematisch ist
edit weil falsch war:
irgendwas^0
immer 1. Somit ist die Mantisse nie Null. Es bleibt nun übrig, die Basis sehr klein zu wählen, oder den Exponenten entsprechend klein zu machen. -> Führt zu einer Rundung.
2. Problem:
Desweiteren ist es eine Herausforderung, eine Basis UND einen Exponenten zu finden, die genau 0.2 ergeben. Oder Pi, oder jede andere uns geläufige Zahl.
Für uns ist eine Zahl mit 17 mal die 0 als Nachkommastelle eine Null. Für den PC nicht ;)
Grüße
(p.s. alles rein akademisch)
Gammatester - Di 03.05.11 14:53
KleinesPferd hat folgendes geschrieben : |
...
1. Problem: Null-Darstellung
Mathematisch ist 0^(irgendwas) immer 1. Somit ist die Mantisse nie Null. Es bleibt nun übrig, die Basis sehr klein zu wählen, oder den Exponenten entsprechend klein zu machen. -> Führt zu einer Rundung. |
Falsch: erstens ist 0^(irgendwas) fast immer 0 für irgendwas >=0, mit der Ausnahme 0^0. Zweitens ist 0 = 0*Basis^irgendwas, normalerweise nimmt man aber als Exponent 0.
KleinesPferd hat folgendes geschrieben : |
Für uns ist eine Zahl mit 17 mal die 0 als Nachkommastelle eine Null. Für den PC nicht ;) |
Falsch: Das ist auch für den PC so. Außerdem ist 17 nur die ungefähre Genauigkeit für Double (Extended hätte ca. 19); aber selbstverständlich sind viel kleinere Zahlen darstellbar bis ca 10^-308.
Gerd Kayser - Di 03.05.11 15:01
KleinesPferd hat folgendes geschrieben : |
Mathematisch ist 0^(irgendwas) immer 1. |
Meine Schulzeit liegt zwar fast 40 Jahre zurück, aber das kann nicht stimmen, denn 0 * 0 ist 0.
Du meinst wohl "x hoch 0", denn das wäre immer 1 (wenn ich mich noch richtig daran erinnere).
KleinesPferd - Di 03.05.11 15:13
Ich seh grad, da hab ich was verwechselt *arg* Besonders weil die Mantisse nie 0 ist, sondern zw 1 und 2.
Ja ich meine x^0 ist 1 ... Ich bitte um Entschuldigung.
Auch wollte ich nicht auf die Feinheiten von Double oder Extended oder sonst was hinaus, sondern den generellen Aufbau einer Fließkommazahl anreißen. Damit der TE nachvollziehen kann, warum dort E-17 steht. Denn nicht jeder der hier im Forum liest und schreibt, ist dem Prinzip Fließkommazahl mächtig. Und nicht jeder der den Text von cr.yp.to überfliegt, versteht auf Anhieb den Sinn dahinter. Wenn jemals die Zeit gefunden wird sich da reinzulesen.
Mag ja sein, das mit extended viele Annehmlichkeiten eingezogen sind. Grundprinzip ist trotzdem geblieben.
Auch wenn dein Hinweis richtig ist, finde ich, das du mit Kanonen auf Spatzen schiesst ;)
Kha - Di 03.05.11 20:15
KleinesPferd hat folgendes geschrieben : |
Auch wenn dein Hinweis richtig ist, finde ich, das du mit Kanonen auf Spatzen schiesst ;) |
Es bleibt aber dabei, dass Gammatester als
einziger den wirklichen Grund für den "Bug", nämlich die Vermischung verschiedener Genauigkeiten, genannt hat. Spitzfindigkeit zahlt sich manchmal aus ;) .
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!