Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Extended rundet bei Addition automatisch (https://www.delphipraxis.net/167336-extended-rundet-bei-addition-automatisch.html)

Delphi-Narr 24. Mär 2012 21:29

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!

himitsu 24. Mär 2012 21:32

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)

jaenicke 24. Mär 2012 21:35

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.

himitsu 24. Mär 2012 21:52

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:
                   12
0,0000000000000000025

1
1,0

also
1 234567890123456789 = Dezimalstellen
1,000000000000000003 = Ergebnis
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.

Nja, mit 1,... sind es etwa 19 signifikante Dezimalstellen, wärend 4,... nur 18 Dezimalstellen ergibt.

Panthrax 25. Mär 2012 01:07

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.

http://de.wikipedia.org/wiki/Gleitko..._absorption.29

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.

Delphi-Narr 25. Mär 2012 10:47

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!

Panthrax 25. Mär 2012 11:17

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.

himitsu 25. Mär 2012 12:44

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);

Medium 25. Mär 2012 15:36

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 ;))

gammatester 25. Mär 2012 17:09

AW: Extended rundet bei Addition automatisch
 
Wenn es nur um Summation geht, kannst Du meine aus meiner AMath-Unit die Funktionen
Delphi-Quellcode:
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}
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".


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