Home » Tipps & Tricks » Mathematik » Arithmetik » Arithmetisch korrekt runden

Arithmetisch korrekt runden

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.