![]() |
Re: Gleitpunktarithmetik - Diskrepanzen
Probiers aus.
|
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: ------------------- |
Re: Gleitpunktarithmetik - Diskrepanzen
Einen hab ich noch: Kein Vergleich, keine 0, nur simples Addieren. Alle Zwischenergebnisse innerhalb des Wertebereiches.
Delphi-Quellcode:
Was kommt raus (x + 10000*0.1 - 10000*0.1 = ?)
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; Bei Extended muss man ca. 500x öfter rechnen. Kann es sein, das auch die 0.1 nicht 100%ig akkurat dargestellt werden kann? |
Re: Gleitpunktarithmetik - Diskrepanzen
Das Ergebnis ist sicher nicht x 8)
Ich habe ![]() 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. |
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:
Besonders interessant finde ich die Lösung im .NET-Framework für genaue Fließkommazahlen:
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; ![]() |
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. |
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 |
Re: Gleitpunktarithmetik - Diskrepanzen
@negaH: So logisch einfach hab ich das noch nie gesehen. :thumb:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 05:28 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz