Arithmetisch korrekt runden |
|
| System | Win9x, WinNT, Win2000, WinXP, Vista, Win7 |
|---|---|
| Ab Delphi-Version | Delphi 1 |
| Letzte Änderung | 28.09.2010 |
Bei der Funktion Round, die in Delphi zur Verfügung steht, ist Folgendes zu beachten: Liegt der Nachkommateil genau in der Mitte zwischen zwei ganzen Zahlen, wird immer die gerade Zahl zurückgeliefert. Dieses Vorgehen beim Runden wird auch als "Banker's rounding" bzw. mathematische Rundung bezeichnet.Das entspricht nicht dem arithmetischen Runden, bei dem bei x,5 auf die nächste ganze Zahl aufgerundet wird. So etwas lässt sich aber leicht nachbauen:
uses
Math;
function ArithRound(Value: Extended): Int64;
var
TmpSign : TValueSign;
begin
TmpSign := Sign(Value);
if TmpSign = ZeroValue then
Result := 0
else
Result := Trunc(Abs(Value) + 0.5) * TmpSign;
end;
Für das Runden von Gleitkommazahlen stehen in Delphi die Funktionen RoundTo und SimpleRoundTo zur Verfügung. Aber auch diese Funktionen liefern nicht die korrekten Ergebnisse. Das arithmetische Rundungsverfahren von Gleitkommazahlen ist folgendermaßen definiert:
''Beim Runden wird die letzte Stelle, die nach dem Runden noch bei der Zahl verbleibt, Rundestelle genannt. Für das Runden gilt nach DIN 1333 folgende Regel: Steht hinter der Rundestelle eine der Ziffern 0 bis 4, so wird abgerundet, steht hinter der Rundestelle eine der Ziffern 5 bis 9, so wird aufgerundet.''
Diese Methode wird auch als kaufmännisches Runden bezeichnet.
uses
Math;
type
TArithRoundToRange = -37..37;
function ArithRoundTo(Value: Extended; Digit : TArithRoundToRange): Extended;
const
Resolution : Extended = 1E-19 * 1000;
Adjustment : Extended = 0.5;
var
Factor : Extended;
TmpSign : TValueSign;
Mode : TFPURoundingMode;
begin
TmpSign := Sign(Value);
if TmpSign = ZeroValue then
Result := 0
else
begin
Factor := IntPower(10, Digit);
Mode := GetRoundMode;
SetRoundMode(rmUp);
try
Result := Int((Abs(Value) + Resolution) / Factor + Adjustment) *
Factor * TmpSign;
finally
SetRoundMode(Mode);
end;
end;
end;
Die Funktion ArithRoundTo rundet eine Gleitkommazahl auf eine bestimmte Potenz von 10, die im Parameter Digit angegeben wird. Um ein möglichst genaues Ergebnis zu erhalten und Rundungsfehler so gering wie möglich zu halten, wird der Rundungsmodus der Gleitkommaeinheit (FPU) mit SetRoundMode angepasst. Die Funktion Sign bestimmt das Vorzeichen eines Gleitkommawertes und ist in der unit Math implementiert.