Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Gleitpunktarithmetik - Diskrepanzen (https://www.delphipraxis.net/59179-gleitpunktarithmetik-diskrepanzen.html)

mumu 18. Dez 2005 22:21


Gleitpunktarithmetik - Diskrepanzen
 
warum erhalte ich für folgende x und y werte (x = 1.5e30 und y = 2e10) solche unterschiedliche werte, obwohl die gleichungen eigentlich äquivalent sein sollten.
a) result = x * y + (3-x) * y - y;
= -2.0E10
b) result = 2 * y;
= 4.0E10

gruß

dizzy 19. Dez 2005 02:38

Re: Gleitpunktarithmetik - Diskrepanzen
 
Das Problem lässt sich auf folgenden Teilterm verkürzen, in dem falsch gerechnet wird: (3-x)


Und da ist es ein Problem der Genauigkeit denke ich. x hat 31 Stellen, aber selbst Extended ist nur auf bis zu 20 Stellen genau. Somit wird intern durch Rundung aus (3-x) einfach (-x), da die 3 viel zu klein ist, um das Ergebnis signifikant zu ändern. Sie stünde nämlich weit hinter der 20. Stelle die maximal noch genau wäre.
Und diese Kleinigkeit führt zu deinem Phänomen. Kleine Ursache, extreme Wirkung :D. Ein hervorragendes Beispiel dafür, warum es sich fast immer lohnt Terme so weit wie möglich zu vereinfachen in der Informatik ;)


Gruss,
Fabian

mumu 19. Dez 2005 06:34

Re: Gleitpunktarithmetik - Diskrepanzen
 
ja genau das hab ich mir eigentlich auch gedacht, dass die 3 so klein ist, dass sie in dem zwischenterm 3-x nicht ins gewicht fällt und bei der genauigkeit nicht mit einbezogen werden kann.

ich habe die aufgabe aus dem studium und bei der aufgabe steht folgendes dabei:
wie erklärt sich die auftretende diskrepanz zwischen den beiden ergebnissen, obwohl x und y und sämtliche zwischenergebnisse hier noch weit innerhalb der double genauigkeit liegen?????

hä?? das versteh ich jetzt halt wieder net? 3-x kann ja für x = 1.5e30 eben nicht durch die Anzahl der Stellen beim Double format repräsentiert werden und muss deshalb gerundet werden.

oder?

alzaimar 19. Dez 2005 06:49

Re: Gleitpunktarithmetik - Diskrepanzen
 
Rechne doch einfach mal mit der Annahme, das (3-x) = -x ist (bei Extended, wohlgemerkt).
Code:
result = x * y + (3-x) * y - y;
result = x * y + ( -x) * y - y;
result = x * y -    x * y - y;
result =                  - y;
q.e.d

mumu 19. Dez 2005 08:32

Re: Gleitpunktarithmetik - Diskrepanzen
 
stimmt alzaimar, das macht sinn.

mich würde jedoch trotzdem interessieren, wie ist die fragestellung zu verstehen ist? was hat sich der prof dabei gedacht?
Zitat:

wie erklärt sich die auftretende diskrepanz zwischen den beiden ergebnissen, obwohl x und y und sämtliche zwischenergebnisse hier noch weit innerhalb der double genauigkeit liegen?????

dizzy 19. Dez 2005 09:53

Re: Gleitpunktarithmetik - Diskrepanzen
 
Die Fragestellung zeugt meiner Meinung nach von Unsauberkeit des Profs. Die Zwischenergebnisse liegen bei weitem eben nicht im Genaugkeitsbereich von Double. Die konstanten Werte von x und y tun dies, aber nicht (3-x)! Da hat der gute wohl böse gepatzt :roll:

mumu 19. Dez 2005 12:35

Re: Gleitpunktarithmetik - Diskrepanzen
 
jo dizzy scheint mir irgendwie auch so, durch den satz, dass zwischenergebnisse im bereich von double liegen wird ja im endeffekt die ganze aufgabe unsinnig...

oder kann es noch nen anderen grund für die ergebnisse von oben geben?

mumu 19. Dez 2005 13:37

Re: Gleitpunktarithmetik - Diskrepanzen
 
naja gut, oder er hat gemeint, dass die zwischenergebnisse im genauigkeitsbereich von double liegen, da sie ja gerundet werden :-)

das wär aber auch leicht hohl?! :-)

alzaimar 19. Dez 2005 14:15

Re: Gleitpunktarithmetik - Diskrepanzen
 
Nee, stimmt nicht. Oder doch. äh... :gruebel:

Er meint den Wertebereich, schreibt aber etwas über Genauigkeit. Schon pervers. :stupid:
Viel hübscher ist das hier (würde ich ihm als Friedensangebot überreichen):
Delphi-Quellcode:
Var
  x : Extended;

begin
  x:=-0.3;
  while x<0.2 do begin
    if x=0 then
      memo.lines.add('[:-)')
    else
      memo.Lines.Add(FloatToStr(x));
    x := x+0.1;
    End;
end;
Frage: Erscheint der/das/die Smiley?
Wenn ja, warum?
Und wenn nein: Verdammt, warum nicht?

Hier liegt Alles im grünen Bereich, sämtliche Zwischenergebnisse, Startwerte etc.
Oder vielleicht doch nicht?

mumu 19. Dez 2005 14:33

Re: Gleitpunktarithmetik - Diskrepanzen
 
stimmt, er mein höchstwahrscheinlich den wertebereich :-)

hmm kann schon sein, dass der Smilie nicht angezeigt wird. evtl wird ja der wert nicht 100%ig auf null gerundet, oder so, keine ahnung?!

alzaimar 19. Dez 2005 14:47

Re: Gleitpunktarithmetik - Diskrepanzen
 
Probiers aus.

dizzy 19. Dez 2005 14:51

Re: Gleitpunktarithmetik - Diskrepanzen
 
Lösung des Problems (markieren zum Lesen):


Die 0 ist als Float (Single, Double, Extended, ...) garnicht darstellbar ;). Für die 0 wird in der FPU ein separates Flag pro Register mitgeführt, und es ist so gut wie nie der Fall, dass eine Berechnung exakt 0 ergibt (eben wegen der üblichen Ungenauigkeit bei Floats). Deswegen gilt auch: Prüfe ein Float nie dirket auf Gleichheit mit 0! (bzw. überhaupt nicht direkt auf Gleichheit)

"Hier liegt Alles im grünen Bereich, sämtliche Zwischenergebnisse, Startwerte etc.
Oder vielleicht doch nicht?"

All diese Werte liegen folglich im Bereich, jedoch nicht der Wert mit dem verglichen wird - der 0! :zwinker:


-------------------

alzaimar 19. Dez 2005 16:39

Re: Gleitpunktarithmetik - Diskrepanzen
 
Einen hab ich noch: Kein Vergleich, keine 0, nur simples Addieren. Alle Zwischenergebnisse innerhalb des Wertebereiches.
Delphi-Quellcode:
Var
  x : Double;
  i : Integer;
begin
  x:=-1;
  For i:=1 to 10000 do x := x + 0.1;
  For i:=1 to 10000 do x := x - 0.1;
  memo.lines.add (FloatToStr(x));
end;
Was kommt raus (x + 10000*0.1 - 10000*0.1 = ?)
Bei Extended muss man ca. 500x öfter rechnen. Kann es sein, das auch die 0.1 nicht 100%ig akkurat dargestellt werden kann?

dizzy 19. Dez 2005 16:54

Re: Gleitpunktarithmetik - Diskrepanzen
 
Das Ergebnis ist sicher nicht x 8)

Ich habe hier schon mal 0.2 binär dargestellt, und es wurde periodisch. Unter der Annahme dass eine halbierte periodische Zahl weiterhin periodisch ist, würde dies auch auf 0.1d zutreffen. Dadurch passt die Mantisse nicht in die dafür vorhandenen Bits (müssten ja unendlich viele sein :stupid:), und schon allein das hinterlegen des Wertes "0.1" in der FPU erzeugt eine Ungenauigkeit. Diese summiert sich auf, und wird aber nicht in gleicher Weise wieder abgezogen in der 2. Schleife! Ungenauigkeiten bei Floats haben so die Eigenschaft mit jeder weiteren Rechnung immer schlimmer zu werden als besser :D
Folglich wird das Ergebnis nachher x+-e heissen, wobei e eine beliebige kleine (nicht beliebig kleine! ;)) reelle Zahl ist, wenn nur ausreichend Zwischenschritte ausgeführt werden.

Khabarakh 19. Dez 2005 17:49

Re: Gleitpunktarithmetik - Diskrepanzen
 
Ich finde das Thema rationale Zahlen in binärer Schreibweise ziemlich interessant, vor allem da es nicht im Schulstoff vorkommt (ganze binäre Zahlen schon in der 5.) und ich ohne Real/Double gar nicht wüsste, dass es so etwas gibt :stupid: . Solche Zahlenkolonnen wie "01110100010" kommen einem ja bekannt vor, aber "11,010" ist ersteinmal doch etwas ungewohnt.
Folgendes lässt sich ja problemlos kompilieren:
Delphi-Quellcode:
begin
  x:=-0.5;
  while x<0.2 do begin
    if x=0 then
      memo.lines.add('[:-)')
    else
      memo.Lines.Add(FloatToStr(x));
    x := x+0.125;
    End;
end;
Besonders interessant finde ich die Lösung im .NET-Framework für genaue Fließkommazahlen: m * 10 ^ -e

alzaimar 19. Dez 2005 19:49

Re: Gleitpunktarithmetik - Diskrepanzen
 
dizzy: Du weisst mehr als ich. Ich wusste nur, das 0.1 nicht exakt dargestellt ist (periodisch)... Ich hab vor 25 Jahren diese Floating-Point Macken erlebt, als unser damalige Rechner (ein HP 9845) durch einen HP300 (mit Motorola 68k) ausgetauscht wurde und die Rechnungen statt mit BCD in der wesentlich schnelleren Floating-Point Arithmetik durchgeführt wurden.

Es ist auf jeden Fall ein sehr wichtiger Aspekt, wenn man weiss, das man zwar schnell rechnen kann, aber das Ergebnis mit einer gehörigen Portion Argwohn betrachten sollte. Bei komplexen Berechnungen, insbesondere iterativen Näherungen, kann sich der anfänglich marginale Fehler sehr schnell in den 1E-5er Bereich potenzieren, was dann gar nicht mehr lustig ist. Man muss dann z.B. die Vorgaben erst normalisieren, also in die Nähe von 1-100 bringen, um den Fehler wieder zu minimieren. Im Extremfall klappt das aber auch nicht.

negaH 20. Dez 2005 05:40

Re: Gleitpunktarithmetik - Diskrepanzen
 
Extended geht von 3.6e10^-4951 bis 1.1e10^4932 und hat eine Manitisse von 64 Bit. Die Mantisse kann also nur 2^64 Zahlen korrekt darstellen * Bereich des Exponenten = 2^16 = 2^80.

Aus einem gesammten Zahlenbereich von 2^1024 können nur 2^80 Zahlen exakt in einem Extended gespeichert werden, das sind 0,00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00672 48730 95247 25964 69121 5039 Prozent
== 1/2^944.

Man kann also mit annähernd 100 Prozent davon ausgehen das eine Fließkommaberechnung immer "falsch" rechnet.

Extendend hat 10 Bytes = 10*8 = Speicherbereich 2^80. Der Exponent fasst 16 Bits = 2^16 und Mantisse 64 Bits = 2^64. Maximal speicherbar also 2^64 * 2^16 = 2^80, maximaler Wertebereich der Zahlen 2^(64 * 16) = 2^1024.
2^1024 / 2^80 = 2^944 Zahlen aus dem gesammten Wertebereich des Extended können nicht exakt gespeichert werden.Dabei ist es irrelevant ob man nur mit kleinen Zahlen annähernd 0.0 rechnet, der "Fehler" ist gleichverteilt.

Gruß Hagen

alzaimar 20. Dez 2005 07:35

Re: Gleitpunktarithmetik - Diskrepanzen
 
@negaH: So logisch einfach hab ich das noch nie gesehen. :thumb:


Alle Zeitangaben in WEZ +1. Es ist jetzt 17:13 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz