Autor Beitrag
Daniel L.
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 140
Erhaltene Danke: 14

W7, W8
TurboD Prof, Delphi Community
BeitragVerfasst: Mi 20.06.18 18:26 
Hi,

durch Fliesskommaberechnungen können ja ungenaue Ergebnisse entstehen.

Wie könnte man erreichen, dass ein nicht exaktes Ergebnis einer Fliesskommaberechung immer oberhalb (oder immer unterhalb) des exakten Wertes liegt - aber so genau wie möglich.

Gibts da was von Delphi?

Sonst müsste man wohl die letzte Nachkommazahl um 1 erhöhen (verringern), bzw. das letzte Mantissebit raufsetzen (runtersetzen) - aber das ist nicht so mein Gebiet :gruebel:

Daniel L.

Moderiert von user profile iconTh69: Tippfehler in Titel korrigiert.
Gammatester
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 328
Erhaltene Danke: 101



BeitragVerfasst: Mi 20.06.18 19:27 
user profile iconDaniel L. hat folgendes geschrieben Zum zitierten Posting springen:
Hi,

durch Fliesskommaberechnungen können ja ungenaue Ergebnisse entstehen.

Wie könnte man erreichen, dass ein nicht exaktes Ergebnis einer Fliesskommaberechung immer oberhalb (oder immer unterhalb) des exakten Wertes liegt - aber so genau wie möglich.

Gibts da was von Delphi?

Für einzelne einfache Operation ist das möglich durch Benutzung von docwiki.embarcadero....em.Math.SetRoundMode also zB wie in docwiki.embarcadero....undMode_%28Delphi%29
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
OldRM := GetRoundMode; { Save the original setting for the Round Mode }

  SetRoundMode(rmDown);
  c := a + b;

  SetRoundMode(rmUp);
  c := a + b;

  SetRoundMode(OldRM); { Restore the original Rounding Mode }

Achtung: Dadurch wird zB bei rmUp 1 + 1e-20 > 1! Und dann: Ich habe keine Ahnung, wie weit diese Monotonie-Eigenschaft für kompliziertere Ausdrück gilt. Außerdem ist dringend zu empfehlen, daß die Roundmode-Änderung möglichst lokal bleibt. Man kann global ändern, aber in der Regel hat man dann größere Fehler, oder wie bei Crocodile Dundee: Man kann damit leben, aber es schmeckt besch...
user profile iconDaniel L. hat folgendes geschrieben Zum zitierten Posting springen:
Sonst müsste man wohl die letzte Nachkommazahl um 1 erhöhen (verringern), bzw. das letzte Mantissebit raufsetzen (runtersetzen) - aber das ist nicht so mein Gebiet :gruebel:
In meiner AMath/DAMath-Bibliothek gibt es dafür die Funktionen predx/predd/preds bzw succx/succd/succs. In den Test/Logfiles findest Du auch alle Möglichkeit für +- 1 +- 1e-20 für extended/double/single und alle Modi.

Für diesen Beitrag haben gedankt: icho2099
Daniel L. Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 140
Erhaltene Danke: 14

W7, W8
TurboD Prof, Delphi Community
BeitragVerfasst: Do 21.06.18 23:00 
...hat ne Weile gebraucht, bis ich kapiert habe, dass nach 'SetRoundMode'
bei einer Gleitkommaoperation das eigentliche Runden selber angestossen werden muss (z.B. mit 'RoundTo').
So muss ich die Stelle, an der gerundet wird, selbst entscheiden.

Danke, auch für Hinweis auf den Mathe-Bibliotheken

Gruß -
Daniel L.
Gammatester
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 328
Erhaltene Danke: 101



BeitragVerfasst: Fr 22.06.18 08:36 
user profile iconDaniel L. hat folgendes geschrieben Zum zitierten Posting springen:
...hat ne Weile gebraucht, bis ich kapiert habe, dass nach 'SetRoundMode'
bei einer Gleitkommaoperation das eigentliche Runden selber angestossen werden muss (z.B. mit 'RoundTo').
So muss ich die Stelle, an der gerundet wird, selbst entscheiden.

Nein! Entgegen weit verbreiteten Gerüchten beeinflußt SetRoundMode jede Fließkommaoperation und nicht nur die Funktionen Round/Roundto. Da das Ergebnis von Fließkommaoperationen idR keine darstellbare FPZ ist, wird dann gemäß der eingestellten Rundungsart sofort gerundet.

Mit dem folgenden Programm
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
{$apptype console}
Uses
  math, sysutils;
var
  a,b,c,d: double;
  ic: int64 absolute c;
  id: int64 absolute d;
  OldRM: TFPURoundingMode;
Begin
  OldRM := GetRoundMode;
  SetRoundMode(rmNearest);
  a := 1;
  b := 1e-100;
  c := a+b;
  d := a-b;
  Writeln('n ',c:20:16' ', IntToHex(ic, 16), '   ', d:20:16' ', IntToHex(id, 16));
  SetRoundMode(rmdown);
  a := 1;
  b := 1e-100;
  c := a+b;
  d := a-b;
  Writeln('d ',c:20:16' ', IntToHex(ic, 16), '   ', d:20:16' ', IntToHex(id, 16));
  SetRoundMode(rmup);
  a := 1;
  b := 1e-100;
  c := a+b;
  d := a-b;
  Writeln('u ',c:20:16' ', IntToHex(ic, 16), '   ', d:20:16' ', IntToHex(id, 16));
  SetRoundMode(OldRM);
End.
kann man mit Delphi-eigenen Bordmitteln sehen
ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
C:\TMP>D:\DMX\M6\DCC32 -b rnd2.dpr
Borland Delphi Version 14.0
Copyright (c) 1983,2001 Borland Software Corporation
rnd2.dpr(32)
33 lines, 0.02 seconds, 30632 bytes code, 3205 bytes data.
C:\TMP>rnd2.exe
n   1.0000000000000000 3FF0000000000000     1.0000000000000000 3FF0000000000000
d   1.0000000000000000 3FF0000000000000     0.9999999999999999 3FEFFFFFFFFFFFFF
u   1.0000000000000002 3FF0000000000001     1.0000000000000000 3FF0000000000000
D.h. es wird immer sofort gerundet. Bei rmNearest ist das Ergebnis 1 +- 1e-100 natürlich wieder, bei den anderen Modi sieht man die Unterschiede in der Dezimal- und Hex-Darstellung.

Vergleiche auch meine Posts in www.delphipraxis.net...h-obwohl-gleich.html und www.lazarusforum.de/...php?f=10&t=11620 (Indianer-Frank).

Für diesen Beitrag haben gedankt: Daniel L.
GuaAck
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 307
Erhaltene Danke: 29

Windows 8.1
Delphi 7 Pers.
BeitragVerfasst: Sa 23.06.18 21:20 
Hallo Daniel,

das ist ein interessantes Thema. Ich hatte bisher nur zwei Arten von Rechnungen:

a) Fließkomma reicht aus, letzte Unsicherheit wegen Rundung sind ohne Bedeutung.

b) Rundungsfehler sind nicht tragbar: Dann nutze ich Integer mit entsprechenden Skalierungen, so habe ich alles unter Kontrolle, kann z. B. den Rest einer Division für spätere Berücksichtung merken.

Auf welche Art von Problemen bezieht sich Deine Frage?

Gruß GuaAck
Daniel L. Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 140
Erhaltene Danke: 14

W7, W8
TurboD Prof, Delphi Community
BeitragVerfasst: So 24.06.18 10:46 
user profile iconGuaAck hat folgendes geschrieben Zum zitierten Posting springen:
Auf welche Art von Problemen bezieht sich Deine Frage?

Rundungsfehler haben in meinem Fall gravierende Folgen:

Sehr verkürzt gesagt:
In einer Funktion steht unter einer Quadratwurzel ein komplizierter Term mit vielen Variablen, welche ihrerseits vorher in mehreren Schritten berechnet wurden.
In bestimmten Situationen ist nun der mathematische Wert unter der Wurzel knapp über 0 oder sogar = 0,
wobei dann wegen Rundungsfehlern ein Wert knapp unter 0 entstehen kann.

Erster Ansatz:
Unter die Wurzel einen kleinen Wert Delta0 aufaddieren (z.B. 0.0001),
aber dieser Wert darf mal garnicht soo klein, um muss mal seehr klein seim (damit die Funktion ausreichend genau bleibt) -

Zweiter Ansatz:
Bei jeder einzelnen FliesskommaOp immer kleinstmöglich nach oben bzw. nach unten runden (daher dieser Thread),
wobei dann immer je nach Vorzeichen unterschieden werden muss, in welche Richtung gerundet werden muss.
Was ich von Gammatester gelernt habe, würde das auch wohl so gehen.

Dritte Ansatz:
Ich hab die Anfangsbedingungen meines Progs so eingeschränkt, daß ich mit einem konstanten Delta0 auskomme.
(Es geht um die Berechnung einer Ellipse aus 5 Punkten(x/y) -
Hatte ich für die 5 Punkte Anfagns x und y als double, so sind sie jetzt Ganzzahl und nach oben beschränkt) -
damit kann ich gut leben :)
In der besagten Funktion wird natürlich nach wie vor mit Fliesskommma gerechnet.

user profile iconGuaAck hat folgendes geschrieben Zum zitierten Posting springen:
das ist ein interessantes Thema

... ja, find ich auch, und ziemlich neu für mich...

Vielen Dank an beide,
Daniel L.
Gammatester
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 328
Erhaltene Danke: 101



BeitragVerfasst: So 24.06.18 11:19 
Ein weiterer Ansatz ist, teilweise mit erhöhter Genauigkeit zu rechnen. Das ist zB wichtig, wenn man quadratische Gleichungen lösen will, wo die Eigenschaften wesentlich von Vorzeichen der Diskriminante (d.h. dem Term unter der Quadratwurzel) abhängt, siehe W.Kahan On the Cost of Floating-Point Computation Without Extra-Precise Arithmetic, 2004, www.eecs.berkeley.edu/~wkahan/Qdrtcs.pdf. Das wird inline in meiner AMTools Squad-Funktion benutzt.

Als Prozeduren gibt es diese dbl2 (double-double) und ext2 (double-extended) Arithmetik in AMath/DAMath (www.wolfgang-ehrhard...ctions.html#dblfloat ), benutzt zB in der Compound-Funktion, die damit den gesamten Argumentbereich mit einem maximalen Fehler von 0.5 ulps (RMS 0.21 ulps) abdeckt.