| 
| Autor | Beitrag |  
| Daniel L. 
          Beiträge: 140
 Erhaltene Danke: 14
 
 W7, W8
 TurboD Prof, Delphi Community
 
 | 
Verfasst: 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    Daniel L.
Moderiert von  Th69: Tippfehler in Titel korrigiert. |  |  |  
| Gammatester 
          Beiträge: 328
 Erhaltene Danke: 101
 
 
 
 
 | 
Verfasst: Mi 20.06.18 19:27 
 
	  |  Daniel L. hat folgendes geschrieben  : |  	  | 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 		                       Delphi-Quelltext 
 									| 1:2:
 3:
 4:
 5:
 6:
 7:
 8:
 9:
 
 | OldRM := GetRoundMode; 
 SetRoundMode(rmDown);
 c := a + b;
 
 SetRoundMode(rmUp);
 c := a + b;
 
 SetRoundMode(OldRM);
 |  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...
 	  |  Daniel L. hat folgendes geschrieben  : |  	  | 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   | 
 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.  
          Beiträge: 140
 Erhaltene Danke: 14
 
 W7, W8
 TurboD Prof, Delphi Community
 
 | 
Verfasst: 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 
          Beiträge: 328
 Erhaltene Danke: 101
 
 
 
 
 | 
Verfasst: Fr 22.06.18 08:36 
 
Nein!	  |  Daniel L. hat folgendes geschrieben  : |  	  | ...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.
 | 
  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 
 		                       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
 		                       Quelltext 
 									| 1:2:
 3:
 4:
 5:
 6:
 7:
 8:
 9:
 
 | C:\TMP>D:\DMX\M6\DCC32 -b rnd2.dprBorland 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 
          Beiträge: 378
 Erhaltene Danke: 32
 
 Windows 8.1
 Delphi 10.4 Comm. Edition
 
 | 
Verfasst: 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.  
          Beiträge: 140
 Erhaltene Danke: 14
 
 W7, W8
 TurboD Prof, Delphi Community
 
 | 
Verfasst: So 24.06.18 10:46 
 
	  |  GuaAck hat folgendes geschrieben  : |  	  | 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.
 
 	  |  GuaAck hat folgendes geschrieben  : |  	  | das ist ein interessantes Thema | 
 ... ja, find ich auch, und ziemlich neu für mich...
 Vielen Dank an beide,
 Daniel L. |  |  |  
| Gammatester 
          Beiträge: 328
 Erhaltene Danke: 101
 
 
 
 
 | 
Verfasst: 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. |  |  |  |