Autor |
Beitrag |
Hidden
      
Beiträge: 2242
Erhaltene Danke: 55
Win10
VS Code, Delphi 2010 Prof.
|
Verfasst: Fr 12.07.13 09:18
Hallo,
In einem meiner Projekte habe ich folgende Zuweisung:
Delphi-Quelltext 1:
| x := Trunc( (locX + shift) * FieldW * BufW / ( w * FullW * scale ) ); |
scale ist vom Typ Extended, ansonsten sind alles Integers.
Um das unten beschriebene Problem zu umgehen, könnte ich die hintere Klammer auflösen und die entstehenden Divisionen ggf. etwas nach vorne ziehen (vielleicht auch die vordere Klammer (locX + shift) ausmultiplizieren). Wie gehe ich dabei vor, damit der Wert für x möglichst Stabil ist, d.h. damit er für möglichst viele Variablenbelegungen möglichst nahe am richtigen Ergebnis liegt?
Ich nehme an, dass für Überlauf-Stabilität die Zwischenergebnisse möglichst nahe an 1 liegen sollten (Exponent), ich für Genauigkeit aber möglichst viele der Zwischenergebnisse in Integer-Typen halten will (Mantisse), korrekt?
Zwischenergebnisse nahe an 1 halten: 1:
| x := Trunc( (locX + shift) * ( FieldW / FullW ) * ( BufW / w ) / scale ) ); |
Lange in Integer bleiben: 1:
| x := Trunc( ( (locX + shift) * FieldW * BufW ) / ( ( w * FullW ) * scale ) ); |
Auch wird hier spekuliert, dass die Zwischenergebnisse eine reduzierte Genauigkeit haben (statt einer erhöhten  )
Zum Effekt:
Obwohl alle Variablen positiv sind, ist das Ergebnis negativ
Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9:
| ( x = -144 für
locX = 507 shift = 4578 FieldW = 300 BufW = 1408 w = 1408 FullW = 1500 scale = 7,05219818923083 ) |
Wenn ich diese Werte im Quelltext für die Variablen einsetze ( x := Trunc( (507 + 4578) * 300 * 1408 / ( 1408 * 1500 * 7.05219818923083 ) );, erhalte ich vom Compiler:
Quelltext 1:
| [DCC Error] frmMain.pas(494): E2099 Overflow in conversion or arithmetic operation |
lg,
Daniel
_________________ Centaur spears can block many spells, but no one tries to block if they see that the spell is a certain shade of green. For this purpose it is useful to know some green stunning hexes. (HPMoR)
Zuletzt bearbeitet von Hidden am Fr 12.07.13 09:19, insgesamt 1-mal bearbeitet
|
|
Gammatester
      
Beiträge: 328
Erhaltene Danke: 101
|
Verfasst: Fr 12.07.13 10:02
Zuletzt bearbeitet von Gammatester am Fr 12.07.13 10:13, insgesamt 1-mal bearbeitet
|
|
Hidden 
      
Beiträge: 2242
Erhaltene Danke: 55
Win10
VS Code, Delphi 2010 Prof.
|
Verfasst: Fr 12.07.13 10:15
_________________ Centaur spears can block many spells, but no one tries to block if they see that the spell is a certain shade of green. For this purpose it is useful to know some green stunning hexes. (HPMoR)
Zuletzt bearbeitet von Hidden am Fr 12.07.13 13:59, insgesamt 1-mal bearbeitet
|
|
Martok
      
Beiträge: 3661
Erhaltene Danke: 604
Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
|
Verfasst: Fr 12.07.13 11:38
Langweilige Info zuerst: wenn man alles in Extended rechnet, funktionierts.
In Delphi bestimmt immer der erste Ausdruck einer Kette, in welchen Typ der Compiler das zusammenfasst. Hier also die 507. Was hilft:
Delphi-Quelltext 1:
| x := Trunc( (507.0 + 4578) * 300 * 1408 / ( 1408 * 1500 * 7.05219818923083 ) ); |
Mit Variablen wäre z.b. das eine Lösung:
Delphi-Quelltext 1:
| x:= Trunc((1.0 * locX + FXShift) * FieldWidth * BufW / (w * FullW * FZoomFact)); |
Die 1.0 erzwingt dabei Fließkommaarithmetik, alles ab da passiert auf der FPU.
_________________ "The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."
Für diesen Beitrag haben gedankt: Hidden
|
|
jaenicke
      
Beiträge: 19314
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Fr 12.07.13 12:52
Oder einfach so: Delphi-Quelltext 1:
| x := Trunc( Int64(507 + 4578) * 300 * 1408 / ( 1408 * 1500 * 7.05219818923083 ) ); | Es sollte auch reichen Int64 statt Integer für die Variablen zu nutzen.
Vorausgesetzt der Maximalwert von Int64 wird nicht überschritten, dann geht das natürlich so auch nicht.
Für diesen Beitrag haben gedankt: Hidden, Martok
|
|
GuaAck
      
Beiträge: 378
Erhaltene Danke: 32
Windows 8.1
Delphi 10.4 Comm. Edition
|
Verfasst: Fr 12.07.13 19:19
Dda gibt es noch einen anderen Aspekt:
Die Reihenfolge der Berechnung und auch der "Zeitpunkt" der Typenumwandlung können von der Compilerversion und vielleicht sogar von Optimierungseinstellungen abhängen.
Wenn es also wirklich auf reproduzierbare Ergebnisse ankommt, dann sollte man alles selbst steuern, z. B. wie vorgeschlagen über Zwischenvariable. Diese Zwischenvariable würde ich sogar z. B. im PUBLIC-Teil der Klasse definieren, so dass der Compiler sie auf jeden Fall anlegen und berechnen muss. Evtl. kann man das auch mit einem Compiler-Schalter für den Code-Bereich erzwingen, dass weiß ich aber nicht.
Gruß
GuaAck
|
|
Hidden 
      
Beiträge: 2242
Erhaltene Danke: 55
Win10
VS Code, Delphi 2010 Prof.
|
Verfasst: Fr 12.07.13 20:01
GuaAck hat folgendes geschrieben : | Diese Zwischenvariable würde ich sogar z. B. im PUBLIC-Teil der Klasse definieren, so dass der Compiler sie auf jeden Fall anlegen und berechnen muss. Evtl. kann man das auch mit einem Compiler-Schalter für den Code-Bereich erzwingen, dass weiß ich aber nicht. |
Hmm, da wäre mir lieber dass andere sich beim Lesen des Programms und Verstehen der public-Variablen nicht wundern müssen.
Wenn es so kritisch wird, schaltet man vielleicht lieber Compier-Optimierungen für diese Quelltextstelle ganz aus.
Ich bin ja so wie so der Meinung, dass die kürzeste Lösung die leicht verständlichste und beste ist. Und Zwischenvariable deklarieren plus zuweisen sind schon wieder zwei Zeilen mehr*, wobei man wahrscheinlich mit einem expliziten Cast das selbe Ergebnis erhält(?).
lg,
Daniel
*Es sei denn, es erhöht bei einer langen Rechnung das Verständnis, z.B. durch mehr Übersicht oder Benennung eines Zwischenergebnisses.
_________________ Centaur spears can block many spells, but no one tries to block if they see that the spell is a certain shade of green. For this purpose it is useful to know some green stunning hexes. (HPMoR)
|
|
OlafSt
      
Beiträge: 486
Erhaltene Danke: 99
Win7, Win81, Win10
Tokyo, VS2017
|
Verfasst: Fr 12.07.13 22:35
Die Anzahl Zeilen im Sorcecode ist doch heutzutage mehr als nur irrelevant
Ich würds "ausführlich" - und damit richtig - programmieren und nen Kommentar dazusetzen, wieso ich so schwafelig bin 
_________________ Lies, was da steht. Denk dann drüber nach. Dann erst fragen.
|
|
|