Vor ein paar Tage bin ich an der Arbeit auf ein interessantes Phänomen gestossen, dass mir so bisher noch nicht bewusst war. Wenn man die Math.Round() Methode von .NET verwendet, dann heisst das nicht automatisch, dass bei 1.5 auf 2 und bei 2.5 auf 3 aufgerundet wird. Ein kleines Beispielprogramm zeigt das Verhalten der Math.Round() Methode des .NET Frameworks:
1 2 3 4 5 |
var result = Math.Round(1.5); Console.WriteLine($"1.5 => {result}"); result = Math.Round(2.5); Console.WriteLine($"2.5 => {result}"); |
Und das Ergebnis:
1 2 |
1.5 => 2 2.5 => 2 |
Komisch, irgendwie haben wir das in der Schule doch mal anders gelernt… Die Antwort ist aber ganz einfach, denn in der MSDN Dokumentation steht unter Math.Round(double):
Rundet einen Gleitkommawert mit doppelter Genauigkeit auf den nächsten ganzzahligen Wert.
Im englischen heisst dieses Verfahren „Bankers Rounding“ und hat den Vorteil, dass bei einer Verteilung von Werten das arithmetische Mittel der gerundeten Zahlen gleich dem arithmetischen Mittel der nicht gerundeten Zahlen ist. Um dennoch das von uns gewüschte Verhalten zu erhalten, ist Math.Round() überladen und man kann zusätzlich noch das MidpointRounding mit angeben. Im folgenden Beispiel sieht man dann das umgestellte Programm:
1 2 3 4 5 |
var result = Math.Round(1.5, MidpointRounding.AwayFromZero); Console.WriteLine($"1.5 => {result}"); result = Math.Round(2.5, MidpointRounding.AwayFromZero); Console.WriteLine($"2.5 => {result}"); |
Ergebnis:
1 2 |
1.5 => 2 2.5 => 3 |
Das Problem ist jetzt nicht riesig, aber dennoch ist es ein Verhalten, dem man sich bewusst sein sollte, wenn man mathematische Berechnungen durchführt. In unseren Anwendungen hat es in wenigen Fällen zu abweichenden Ergebnissen geführt und die Math.Round() Methode hatte dabei niemand auf dem Schirm.