Um das Ganze abzuschließen, hier sind gleich mehrere Annahmen falsch.
Beim
Banker's Rounding gibt es eine weitere Regelung für den Fall 0.5.
Zusammengefasst:
- Alle Fälle außer 0.5 verhalten sich identisch zum mathematischen Runden, welches auch in Delphi angewandt wird
- 0.5 wird im normalen Banker's Rounding immer zur nächsten geraden Zahl gerundet
- Alternativ wird 0.5 aufgerundet.
Folgender Code deckt genau dieses Verfahren ab, wobei der letzte Parameter für
True die Rundung in Richtung gerade durchführt und bei
False immer aufrundet.
Delphi-Quellcode:
function BankersRound(const aValue: Double; const aRoundTo: Integer = 2; const aApplyEvenRoundRule: Boolean = True): Double;
var
PositiveValue,
IsEven
: Boolean;
MultipliedValue,
FracValue,
ResolutionDirection
: Double;
const
DOUBLE_RESOLUTION = 1E-12;
begin
if aValue = 0 then
Exit(0);
MultipliedValue := Abs(aValue) * IntPower(10, aRoundTo);
FracValue := Frac(MultipliedValue);
if not System.Math.SameValue(FracValue, 0.5, DOUBLE_RESOLUTION) then
Exit(System.Math.RoundTo(aValue, 0 - aRoundTo));
PositiveValue := aValue > 0;
if aApplyEvenRoundRule then
begin
IsEven := Trunc(MultipliedValue) mod 2 = 0;
if PositiveValue and IsEven then
// > 0 and even
ResolutionDirection := -1
else if PositiveValue then
// > 0 and odd
ResolutionDirection := 1
else if IsEven then
// < 0 and even
ResolutionDirection := 1
else
// < 0 and odd
ResolutionDirection := -1
end
else
begin
if PositiveValue then
ResolutionDirection := 1
else
ResolutionDirection := -1;
end;
Result := System.Math.RoundTo(aValue + ResolutionDirection * DOUBLE_RESOLUTION, -2);
end;
Das gesamte Beispiel inkl. Testfälle ist im Anhang.
...
...