Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - 0.3-0.3<>0 ??


buSC - Di 22.12.09 12:12
Titel: 0.3-0.3<>0 ??
hallo liebe forumer

ich habe in einer stelle in meinem delphi code die Ueberraschung, dass 0.3-0.3=5.5e-17 gehabt wobei je 0.3 inhalt eines double-variables ist.

warum habe ich kein null bekommen ??!!!


im Voraus Danke fuer eure Antwort

Moderiert von user profile iconGausi: Topic aus Algorithmen, Optimierung und Assembler verschoben am Di 22.12.2009 um 11:16
Moderiert von user profile iconNarses: Überflüssige Zeilenumbrüche/Leerzeilen entfernt.


Gausi - Di 22.12.09 12:16

Das sind die üblichen Ungenauigkeiten bei der Darstellung von Float-Werten. Sämtliche dieser Typen sollten nie mit "=" überprüft werden, sondern mit den passenden Funktionen wie IsEqual. Da wird dann Gleichheit bis auf eine gewisse Genauigkeit überprüft.

Zur Ausgabe sollte man passend runden.


buSC - Di 22.12.09 13:05

danke fuer die schnelle Antwort

aber mein Problem ging es nicht um Gleichheit sodern um deise subtraktion 0.3-3.0 die null ergeben musste aber gibt 5.5e-17 zueruck.

wobei je 0.3 in einem double variable im laufe des Programms entstanden ist.

aber ich will null(0) als ergebnis.


danke Im voraus fuer die Antwort

Moderiert von user profile iconNarses: Überflüssige Zeilenumbrüche/Leerzeilen entfernt.


Gausi - Di 22.12.09 13:27

Und genau das geht halt nicht. Man bekommt bei solchen Rechnungen nicht das exakte Ergebnis. Das liegt daran, dass einige Werte, die im Zehnersystem "schön" aussehen, im Dualsystem eben mehr (oder viel mehr) Stellen brauchen. Und dabei kommt es dann zu Rundungsartefakten.

0.3 - 0.3 ist dann nicht gleich 0, sondern nur ungefähr gleich 0. ;-)

Dir bleibt da nur, die Ausgabe auf eine kleinere Genauigkeit zu beschränken (FloatToStrF), oder besondere Ergebnisse nachzuarbeiten.


Gammatester - Di 22.12.09 13:35

Ohne Deine genaue Vorgehensweise kann man nur raten. Wenn d1 und d2 double-Variablen sind, so gilt immer d1 - d1 = 0 und d2 - d2 = 0. Interessant ist z.B.

Delphi-Quelltext
1:
2:
3:
4:
d1 := 0.3;
d2 := 0.1;
d2 := 3*d1;
writeln(d2-d1);

Das Ergebnis ist 5.55111512312578E-0017. Die Erklärung ist folgende: 0.1=1/10 und 0.3=3/10 sind nicht exakt im Binärsystem darstellbar, so wie 1/3 nicht exakt als endliche Dezimalzahl darstellbar ist. Die internen Darstellungen sind

Quelltext
1:
2:
3:
  0.1 = 3FB999999999999A
  0.3 = 3FD3333333333333
3*0.1 = 3FD3333333333334

0.3 und 3*0.1 unterscheiden sich im letzen Bit ungefähr so wie sich 2*(1/3) = 0.6666666666 sich von 2/3 = 0.6666666667 im Dezimalsystem mit 10 Nachkommastellen unterscheiden. Das letzte Bit ergibt die 5.55E-17.

Gruß Gammatester


F34r0fTh3D4rk - Di 22.12.09 22:32

Ich habs jetzt nicht getestet, aber ich bin mir ziemlich sicher, dass 0.3 und 0.3 ohne die Anwendung arithmetischer Operationen die selbe interne Repräsentation haben :mrgreen:.

Beispiel (wie gesagt, ungetestet):

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
var
  a, b, c: double;
begin
  a := 0.3
  b := 0.3
  c := a-b; // = 0.0
end;

Intern würde 0.3 afaik durch 0 01111101 00110011001100110011010(IEE 754) o.Ä. repräsentiert werden (statt double habe ich hier einfach mal float genommen).
Bei der Subtraktion müsste also trotz alledem 0.0 herauskommen.

Ich gehe einfach mal davon aus, dass es so ist, dass in deinen beiden double-Variablen nicht wirklich 0.3 drinsteht und daher das von user profile iconGammatester beschriebene Problem auftritt.