![]() |
Extended rundet bei Addition automatisch
Hallo,
ich habe ein eigentlich recht banales Problem: Ich möchte zu einer Variable des Typs Extended einen weiteren Extended-Wert hinzuaddieren. Der zu addierende Wert ist mit 2,5E-18 sehr klein, ist aber entscheidend. Ist der Ursprungswert meiner Variable X = 0, so ist das Ergebnis korrekt. 0+2,5E-18 ergibt 2,5E-18. Möchte ich jedoch zum Wert X = 1 den Wert addieren, erhalte ich immer noch 1... Wie kann ich dieses Problem beheben? Viele Grüße! |
AW: Extended rundet bei Addition automatisch
Garnicht?
Die signifikanten Stellen, also die Auflösung reicht nicht unbedingt aus. Du brauchst einen anderen Typen, welcher eine höhere Genauigkeit besitzt, oder du mußt deinen Wert auf mehrere Variablen aufteilen. (was quasi auf's Selbe rauskommt) |
AW: Extended rundet bei Addition automatisch
Indem du selbst rechnest, ohne Extended als Typ. Der hat eine zu geringe Genauigkeit. Intern funktioniert die Fließkommadarstellung wie der Name schon sagt, indem das Komma fließt. Die Genauigkeit ist aber begrenzt und ist bei Extended glaube ich 14 Stellen oder so. Solange du nun nur einen Wert 18 Stellen nach dem Komma hast, ist das ok. Das ist eben dieser Wert 18 Stellen nach dem Komma.
Wenn du nun aber einen Wert vor dem Komma hast und der mit den Nachkommastellen addiert wird, ist die Differenz zu groß als dass das in der Genauigkeit darstellbar wäre. Bei solchen hochpräzisen Berechnungen bleibt daher nur diese entweder nach Möglichkeit so zu optimieren, dass sich das Problem nicht stellt oder eine präzisere Berechnung selbst zu implementieren. |
AW: Extended rundet bei Addition automatisch
Extended hat maximal 18-19 signifikante Dezimalstellen. (ungefähr 18,1845... Dezimalstellen)
Die Berechnung liegt also knapp an der Grenze. Es gibt aber einen Unterschied. Der Debugger, FloatToStr usw. runden aber oftmals schon auf 15-16 Stellen, für die Anzeige. (Double) Somit könnte die Berechnung grade noch so stimmen.
Code:
Für die Anzeige könnte aber die 0,00..03 weggerundet werden .... es werden 0,0 angezeigt, aber es sind 1,000000000000000003 vorhanden, was sich prüfen läßt, indem man 18 explizit mit Dezimalstellen anzeigen läßt.
12
0,0000000000000000025 1 1,0 also 1 234567890123456789 = Dezimalstellen 1,000000000000000003 = Ergebnis Nja, mit 1,... sind es etwa 19 signifikante Dezimalstellen, wärend 4,... nur 18 Dezimalstellen ergibt. |
AW: Extended rundet bei Addition automatisch
Dieser Effekt wird auch Absobtion genannt; die größere Zahl absorbiert die kleinere Zahl. Wegen der begrenzten Genauigkeit von Gleikommazahlen, ist dies das beabsichtigte und "natürliche" Verhalten.
![]() Die Möglichkeiten, das zu verhindern sind begrenzt und am Ende steht die Implementierung eines eigenen Typs, der die Genauigkeitsforderungen erfüllt. Vielleicht gibt es aber auch eine andere Lösung, weil "man weiß, was man tut": Ich wollte einmal Zahlenreihen summieren, regelmäßig bestehend aus Zahlen, die nicht alle gleichzeitig in den Genauigkeitsbereich passten. Nachdem eine erste große Zahl vorkam oder die Summe zu groß wurde, wurden alle nachfolgenden, kleinen absorbiert. Aufgrund der Vielzahl der Zahlen war der Fehler für nachfolgende Berechnungen einfach zu groß. Meine Lösung war, erst die Zahlenreihen zu sortieren und dann bei der kleinsten beginnend zu summieren. So haben die kleinen Zahlen ihr Gewicht in der Gesamtberechnung nicht verloren, und der Fehler konnte angemessen reduziert werden. |
AW: Extended rundet bei Addition automatisch
Also einen komplett neuen Typ zu implementieren geht mir für meine Zwecke zu weit...
Ich habe quasi eine Schleife, in der zum Ursprungswert X immer eine kleine Zahl hinzuaddiert wird. Dafür ist das letzte Ergebnis für mich von Bedeutung. Jedes Zwischenergebnis soll auch ausgegeben werden können. Dann muss ich wohl leider die Anzahl der Zwischenergebnisse reduziere, sodass der zu addierende Wert größer wird. Ist für die Genauigkeit zwar nicht so gut, aber immer noch besser als gar keine Veränderung. Danke für die Hilfe! |
AW: Extended rundet bei Addition automatisch
Das klingt doch gut!
Delphi-Quellcode:
var
Summe, KleineSumme, KleinerWert: Extended; // KleinerWert hier nur als Platzhalter { ... } Summe := 1; KleineSumme := 0; for I := 0 to N - 1 do begin KleineSumme := KleineSumme + KleinerWert; // erst die kleinen Werte summieren WriteLn(Summe + KleineSumme); // für die Ausgabe summieren; // irgendwann ist KleineSumme groß genug // und wird nicht mehr absorbiert end; Summe := Summe + KleineSumme; // dann die großen und kleinen Werte summieren. |
AW: Extended rundet bei Addition automatisch
Du könntest sogar noch mehr Ungenauigkeiten rausrechnen.
Delphi-Quellcode:
KleineSumme := 0;
for I := 0 to N - 1 do begin KleineSumme := KleinerWert * I; // erst die kleinen Werte summieren WriteLn(Summe + KleineSumme); // für die Ausgabe summieren; // irgendwann ist KleineSumme groß genug // und wird nicht mehr absorbiert end; Summe := Summe + KleineSumme;
Delphi-Quellcode:
for I := 0 to N - 1 do
begin WriteLn(Summe + (KleinerWert * I)); end; Summe := Summe + (KleinerWert * N); |
AW: Extended rundet bei Addition automatisch
Wenn du nur + und - verwendest, kannst du auch einfach in ein besser aufgelöstes Intervall skalieren, und bei der Ausgabe Exponentialdarstellung nehmen, oder im String ein paar Nullen zwischenpappen. (Dann natürlich am besten um 10er Potenzen skalieren ;))
|
AW: Extended rundet bei Addition automatisch
Wenn es nur um Summation geht, kannst Du meine aus meiner
![]()
Delphi-Quellcode:
benutzen, die Genaugkeit wird dadurch ca verdoppelt. Intern verwenden sie den Algorithmus von "T. Ogita, S.M. Rump, and S. Oishi, Accurate sum and dot product".
function sum2x(const a: array of extended; n: integer): extended;
{-Compute accurate sum(a[i], i=0..n-1) of extended vector} function sum2x(const a: array of extended; n: integer): extended; {-Compute accurate sum(a[i], i=0..n-1) of extended vector} |
Alle Zeitangaben in WEZ +1. Es ist jetzt 09:20 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