Thema: SimpleRoundTo

Einzelnen Beitrag anzeigen

samso

Registriert seit: 29. Mär 2009
439 Beiträge
 
#9

AW: SimpleRoundTo

  Alt 26. Dez 2012, 17:12
Die Floatingpointunit des Prozessors rechnet intern mit dem Typ Extended. Wenn die Zwischenergebnisse im Typ Double gespeichert werden, dann wird auf die geringere Auflösung gerundet (vergleichbar mit einem Taschenrechner der intern mit 12 Stellen rechnet in der Anzeige aber nur 10 Stellen darstellt). Solange ich innerhalb eines Typs bleibe (also Double oder Extended) ist das Endergebnis bei mir korrekt. Erst bei der Mischung der Typen kommt es zu sichtbaren Fehlern. Wenn also a,b vom Typ Extended sind, während f vom Type Double ist, ist der Fehler der Berechnung bei mir so groß, dass das Ergebnis der Rundung falsch ist.
Und dann wird 10,17 ausgegeben. Warum ist das unterschiedlich zu dem Code von Bummi?
Das wäre nur zu erklären, wenn das Ergebnis der Funktion Mult3 nicht 10,175 sondern kleiner wäre. Da der Fehler schon sehr groß sein muss, damit er im Debugger angezeigt wird, käme es vermeintlich zur falschen Rundung. Mit dem folgende Testprogramm habe ich das getestet:
Delphi-Quellcode:
var
  a: Extended;
begin
   a := 10.175 - 5E-10;
   Caption := FloatToStr(SimpleRoundTo(a));
Der Debugger (Delphi 2007/2010) zeigt a=10,175 an, obwohl der Fehler bereits bei 5E-10 liegt, und damit weit oberhalb der eigentlich erreichbaren Genauigkeit von Extended. Mir ist allerdings nicht klar, wie das Ergebnis von Mult3 in diesen Bereich kommen sollte. Ich habe mich redlich bemüht mit diesen Anfangswerten zu diesem Fehlerbild zu kommen - es klappt nicht.
Edit: Die Berechnung (a * b / f) + 0.5 ergibt einen Wert der etwas kleiner als 1018 ist (der Fehler sollte in etwa bei -2e-14 liegen). Bei der Zuweisung auf Double wird nun durch die Floatingpointunit auf 1018 gerundet. Das nachfolgende Trunc liefert dann den korrekten Integer 1018. Unterbleibt die Zuweisung auf Double und wird mit Extended weiter gerechnet, unterbleibt die prozessorinterne Rundung und trunc liefert den "falschen" Wert.

Bei Delphi 2007 war die Funktion SimpleRoundTo wie folgt deklariert:
function SimpleRoundTo(const AValue: Double; const ADigit: TRoundToRange = -2): Double;

Bei Delphi 2009/2010 (spätere Versionen habe ich hier nicht) war es dann
function SimpleRoundTo(const AValue: Extended; const ADigit: TRoundToRange = -2): Extended;

Deshalb liefert die Funktion bei Delphi 2007 noch den korrekten Wert und bei Delphi 2009/2010 dann nicht mehr.

Geändert von samso (27. Dez 2012 um 13:07 Uhr) Grund: Inhaltliche Fehler beseitigt
  Mit Zitat antworten Zitat