Alle
bärtigen Ku, Kameraden!
Wir alle wissen, was Rundung ist. Wenn jemand es vergessen hat, ist Rundung das Ersetzen einer Zahl durch ihren ungefähren Wert, der mit weniger signifikanten Ziffern geschrieben ist. Wenn Sie eine Person im laufenden Betrieb fragen, was passiert, wenn Sie 6,5 auf ganze Zahlen runden, antwortet sie ohne zu zögern mit „7“. Von der Schule wurde uns beigebracht, dass Zahlen auf die nächste ganze Zahl gerundet werden, deren absoluter Wert größer ist. Das heißt, wenn in der gerundeten Zahl der Bruchteil gleich oder größer als die Hälfte der Entladung des gesamten Teils ist, dann runden wir die ursprüngliche Zahl auf die nächstgrößere.
Einfach ausgedrückt:
6,4 = 6 6,5 = 7 6,6 = 7
usw.
Wenn wir die Schule verlassen und Programmierer werden, erwarten wir oft dasselbe Verhalten von unseren leistungsstarken Programmiersprachen. Wir haben völlig vergessen, dass uns in der Schule „mathematisches Runden“ beigebracht wurde, aber tatsächlich gibt es viel mehr Arten von Runden. Allein auf Wikipedia können
Sie ermitteln, wie viele Rundungsoptionen 0,5 auf die nächste Ganzzahl sind:
- Mathematische Rundung
- Zufällige Rundung
- Abwechselnde Rundung
- Bankrundung
Der erste Typ, "mathematische Rundung", haben wir alle aus der Schule gelernt. Sie können nach Belieben über den zweiten und dritten Typ lesen, sie sind für mich heute in diesem Artikel nicht interessant.
Interessant ist jedoch bereits die „Bankrundung“. "Warum?" - Du fragst. Im Subnetz verwenden wir häufig die
Convert- Klasse, die viele Methoden zum Konvertieren eines Datentyps in einen anderen bietet (nicht zu verwechseln mit der Umwandlung, sie wird unten beschrieben). Und jetzt stellt sich heraus, dass beim Konvertieren von Gleitkommazahlen (
double, float, decimal ) in einen Integer-
Int- Typ durch die
Convert.ToInt32- Methode die "Banking"
-Rundung unter der Haube funktioniert. Es wird hier standardmäßig verwendet!
Und es scheint, als würde die Unkenntnis dieser Kleinigkeit Ihre Arbeit nicht stark beeinträchtigen, aber sobald Sie mit Statistiken arbeiten und Indikatoren berechnen müssen, die auf einer Reihe von Aufzeichnungen und Zahlen aller Art basieren, wird diese Sache seitwärts herauskommen. Weil wir (aus Unwissenheit) erwarten, dass alle unsere Umrechnungen / Rundungen in den Berechnungen nach den Regeln der "mathematischen" Rundung funktionieren. Und wir sehen aus wie ein Widder auf einem neuen Tor für das Ergebnis der Rundung
6.5 , also
6 .
Der erste Gedanke des Programmierers, der dies sieht, lautet: „Vielleicht funktioniert das Runden in die entgegengesetzte Richtung, und nach den Regeln wird auf die kleinste Zahl gerundet?“, „Vielleicht habe ich etwas aus der Schulmathematik vergessen?“. Dann geht er zu Google und versteht, dass sie nichts vergessen haben und dass eine Art Mob vor sich geht. In diesem Schritt entscheidet der faule Entwickler, dass dies das Standardverhalten der
Convert.ToInt32- Methode ist, auf die kleinste Ganzzahl
gerundet und für die weitere Suche
bewertet wird. Und er wird denken, dass wenn
Convert.ToInt32 (6,5) =
6 , dann analog
Convert.ToInt32 (7,5) =
7 . Aber da war es. In Zukunft werden solche Entwickler mit einer Reihe von Fehlern aus der QS-Abteilung auf den Kopf getroffen.
Tatsache ist, dass das "Bank" -Runden etwas schwieriger funktioniert - es rundet eine Zahl auf die nächste gerade ganze Zahl und nicht auf die nächste ganze Zahl modulo. Diese Art der Rundung ist angeblich ehrlicher, wenn sie im Bankgeschäft angewendet wird - Banken werden sich selbst oder Kunden nicht berauben, vorausgesetzt, es gibt so viele Operationen mit einem geraden ganzzahligen Teil wie Operationen mit einem ungeraden ganzzahligen Teil. Aber was mich
betrifft - es ist immer noch unklar :) Deshalb gibt
Convert.ToInt32 (6.5) ein Ergebnis von
6 und das Ergebnis für
Convert.ToInt32 (7.5) ist
8 , nicht 7 :)
Was tun, um alle mit der „mathematischen“ Rundung vertraut zu machen?
Konvertierungsklassenmethoden haben keine zusätzlichen Rundungsoptionen. Es ist wahr, weil diese Klasse hauptsächlich nicht zum Runden, sondern zur Typkonvertierung dient. Die wunderbare
Matheklasse mit ihrer
Rundenmethode kommt zur Rettung. Aber auch hier ist Vorsicht
geboten , da diese Methode standardmäßig genauso funktioniert wie das Runden in
Convert.ToInt32 () - gemäß der "Banking" -Regel. Dieses Verhalten kann jedoch mit dem zweiten Argument geändert werden, das Teil der
Round- Methode ist.
Math.Round (someNumber, MidpointRounding.ToEven ) gibt uns also die Standardrundung "Banking". Aber
Math.Round (someNumber, MidpointRounding.AwayFromZero ) funktioniert nach den üblichen Regeln der "mathematischen" Rundung.
Übrigens verwendet
Convert.ToInt32 () System.Math.Round () nicht unter der Haube. Das spezielle Ausgraben der
Implementierung dieser Methode zur Github-Rundung wird anhand der Rückstände betrachtet:
public static int ToInt32(double value) { if (value >= 0) { if (value < 2147483647.5) { int result = (int)value; double dif = value - result; if (dif > 0.5 || dif == 0.5 && (result & 1) != 0) result++; return result; } } else { if (value >= -2147483648.5) { int result = (int)value; double dif = value - result; if (dif < -0.5 || dif == -0.5 && (result & 1) != 0) result--; return result; } } throw new OverflowException(Environment.GetResourceString("Overflow_Int32")); }
Und zum Schluss noch ein paar Worte zum
Typ Casting :
var number = 6.9; var intNumber = (int)number;
In diesem Beispiel habe ich einen Gleitkommatyp (in diesem Fall
double ) in eine Ganzzahl
int umgewandelt . Beim Casting in eine Ganzzahl wird der gesamte nicht ganzzahlige Teil
einfach abgeschnitten . Dementsprechend enthält in diesem Beispiel die Variable "
intNumber "
die Nummer
6 . Hier gibt es keine Rundungsregeln, sondern nur alles, was nach dem Dezimalpunkt steht. Denken Sie daran!
Verwandte Links:
PS Vielen Dank an Maxim Yakushkin, der auf diesen impliziten Moment aufmerksam gemacht hat.
PPS Übrigens funktioniert das Runden in
Python standardmäßig auf Bankbasis genauso. Vielleicht ist das Gleiche in deiner Sprache, sei vorsichtig mit Zahlen :)