Warum verwendet .NET standardmäßig die Rundung von Bankern?

271

Der Dokumentation zufolge verwendet die decimal.RoundMethode einen Round-to-Even-Algorithmus, der für die meisten Anwendungen nicht üblich ist. Daher schreibe ich immer eine benutzerdefinierte Funktion, um den natürlicheren Round-Half-Up-Algorithmus auszuführen:

public static decimal RoundHalfUp(this decimal d, int decimals)
{
    if (decimals < 0)
    {
        throw new ArgumentException("The decimals must be non-negative", 
            "decimals");
    }

    decimal multiplier = (decimal)Math.Pow(10, decimals);
    decimal number = d * multiplier;

    if (decimal.Truncate(number) < number)
    {
        number += 0.5m;
    }
    return decimal.Round(number) / multiplier;
}

Kennt jemand den Grund für diese Entscheidung zum Framework-Design?

Gibt es eine integrierte Implementierung des Round-Half-Up-Algorithmus in das Framework? Oder vielleicht eine nicht verwaltete Windows-API?

Es könnte für Anfänger irreführend sein, einfach zu schreiben decimal.Round(2.5m, 0), 3 als Ergebnis zu erwarten, aber stattdessen 2 zu bekommen.

Darin Dimitrov
quelle
105
Aufrunden ist nicht "natürlicher". Die Natur hat nichts damit zu tun. Es ist einfach das, was Sie in der Grundschule gelernt haben, als Sie das Konzept des "Runden" gelernt haben. Der Schulunterricht zeichnet nicht immer ein vollständiges Bild.
Rob Kennedy
45
@ Rob Und deshalb ist es natürlicher , obwohl es nicht richtig ist
Pacerier
10
Ich verstehe nicht, @Pacerier. Ich habe erklärt, warum es nicht natürlich ist, und Sie sagen, dass es tatsächlich so ist , warum es natürlich ist. Wie wirkt meine Argumentation gegen meine Schlussfolgerung, die das Gegenteil von Ihrer ist? Dinge, an die Sie sich gewöhnt haben, fühlen sich vielleicht natürlich an, und manchmal sagen wir im übertragenen Sinne, dass etwas "zweite Natur" ist, aber das macht sie nicht natürlich.
Rob Kennedy
16
@ Rob Ich sage, es ist natürlich, weil es sich natürlich anfühlt. Sie wissen , dass es 36 verschiedene Objekte mit demselben Variablennamen sind natürlich nicht wahr?
Pacerier
9
Die Natur ist definitiv analog, also ist es das falsche Wort. aber das ist pedantisch. Vielleicht wäre 'üblich' ein besseres Wort. "Was ist die übliche Rundung, die Leute machen
?

Antworten:

196

Wahrscheinlich, weil es ein besserer Algorithmus ist. Im Verlauf vieler durchgeführter Rundungen werden Sie herausfinden, dass alle .5er gleich hoch und runter runden. Dies gibt bessere Schätzungen der tatsächlichen Ergebnisse, wenn Sie beispielsweise eine Reihe gerundeter Zahlen hinzufügen. Ich würde sagen, obwohl es nicht das ist, was manche erwarten, ist es wahrscheinlich das Richtige.

Kibbee
quelle
71
vorausgesetzt, Sie haben natürlich eine flache Verteilung von ungeraden und geraden Eingaben
jk.
7
+1 für einen besseren Algorithmus , obwohl Ostemar die eigentliche Antwort hat ( stackoverflow.com/questions/311696/… )
Ian Boyd
2
@ Ian, ich gebe diese Antwort auch +1. Auf jeden Fall können wir die "akzeptierte Antwort verschieben" bekommen. Vielleicht kann das OP dies tun. Die eigentliche Antwort auf das "Warum", das diese Methode verwendet, befindet sich auf halber Strecke. Obwohl ich den Wiederholungsschub sehr mag, bekomme ich ungefähr einmal pro Woche von dieser Antwort.
Kibbee
@ Kibbee - danke, dass du meine Antwort hochgeschoben hast. Ich denke, es liegt an der OP, die akzeptierte Antwort nach eigenem Ermessen zu ändern.
Ostemar
-1 für die Angabe, dass es ein besserer Algorithmus ist. - Bei einer zufälligen Stichprobenauswahl mit Bankrundung erhalten Sie am Ende mehr Zahlen an geraden als an ungeraden Positionen. - Erst wenn Sie diese Zahlen gemittelt haben, erhalten Sie wieder einen ähnlichen Spread wie bei der ursprünglichen Verteilung. - Wenn Sie diese Daten jedoch beispielsweise in einem Streudiagramm darstellen würden, könnte eine künstliche Gruppierung auftreten.
Paul23
437

Die anderen Antworten mit Gründen, warum der Banker-Algorithmus (auch bekannt als Round Half to Even ) eine gute Wahl ist, sind ganz richtig. Es leidet nicht so sehr unter einer negativen oder positiven Verzerrung wie die runde Hälfte von der Nullmethode über die meisten vernünftigen Verteilungen.

Die Frage war jedoch, warum .NET die tatsächliche Rundung von Banker als Standard verwendet - und die Antwort lautet, dass Microsoft den IEEE 754- Standard befolgt hat . Dies wird auch in MSDN für Math.Round unter Bemerkungen erwähnt.

Beachten Sie auch, dass .NET die von IEEE angegebene alternative Methode unterstützt, indem es die MidpointRoundingAufzählung bereitstellt . Sie hätten natürlich mehr Alternativen zur Lösung von Bindungen bieten können , aber sie entscheiden sich dafür, nur den IEEE-Standard zu erfüllen.

Ostemar
quelle
17
Warum folgt IEEE 754 der Rundung von Bankern? Diese (immer noch gute) Antwort geht nur am Eimer vorbei.
Henk Holterman
4
@HenkHolterman Wahrscheinlich aufgrund dessen, was in den anderen Antworten erwähnt wird (und wie ich zusammengefasst habe); Es leidet nicht (zu sehr) unter einer negativen oder positiven Verzerrung und ist daher für die meisten Verteilungen und Problembereiche ein vernünftigerer Standard.
Ostemar
Ich finde es interessant, weil IEEE 754 der Standard für Gleitkommazahlen ist, von denen Decimal nicht ist. Vielleicht folgt es IEEE 754, so dass der gleiche Algorithmus zum Runden von Double as Decimal verwendet wird.
Brandon Barkley
1
@BrandonBarkley Eine Dezimal- oder Dezimalzahl ist eine Gleitkommazahl, und IEEE 754 enthält dezimale Gleitkommazahlen.
Pablo H
88

Obwohl ich die Frage "Warum haben die Designer von Microsoft dies als Standard gewählt?" Nicht beantworten kann, möchte ich nur darauf hinweisen, dass eine zusätzliche Funktion nicht erforderlich ist.

Math.RoundMit dieser Option können Sie Folgendes angeben MidpointRounding:

  • ToEven - Wenn eine Zahl auf halbem Weg zwischen zwei anderen liegt, wird sie auf die nächste gerade Zahl gerundet.
  • AwayFromZero - Wenn eine Zahl auf halbem Weg zwischen zwei anderen liegt, wird sie auf die nächste Zahl gerundet, die von Null entfernt ist.
Michael Stum
quelle
8
Und wie ich in verwandten Threads erwähnt habe, stellen Sie sicher, dass Sie in Ihrer Rundung konsistent sind. Wenn Sie manchmal in der Datenbank und manchmal in .net runden, treten seltsame Fehler von einem Cent auf, für die Sie Wochen benötigen finde es heraus.
Chris
59
Ein Kunde hat mir einmal über 40.000 US-Dollar gezahlt, um einen Rundungsfehler von 0,11 US-Dollar zwischen zwei Zahlen aufzuspüren, die beide nur knapp 1 Milliarde US-Dollar wert waren. Die $ 0,11 waren auf einen Unterschied im Rundungsfehler der 8. Stelle zwischen einem Mainframe und SQL Server zurückzuführen. Sprechen Sie über einen Perfektionisten!
EJ Brennan
12
@ EJB - Ich wäre wahrscheinlich ein Perfektionist, wenn ich mit einer Milliarde Dollar zu
tun hätte ;-)
12
@ EJ Brennan: Sie haben 40.000 US-Dollar gebraucht, um das herauszufinden? Ich sehe ständig solche Probleme, Rundung ist Ursache Nr. 1, Double / Float-Normalisierung ist Ursache Nr. 2, Programmiererfehler Nr. 3 - Nr. 3 kann sofort auf Nr. 1 gesetzt werden, wenn keine vordefinierten Testfälle vorhanden sind. Übrigens, können Sie mich bitte mit Ihrem Milliardärskunden in Kontakt bringen? Ich glaube, ich könnte noch ein paar weitere 40.000-Dollar-Fehler in seinem System finden! : D
3
@ Seanxe: Oder wenn Sie Büroräume gesehen hätten. Im Ernst, wenn Sie mysteriöse, winzige Ungenauigkeiten im Geld sehen, ist es fast immer eine gute Idee, das Rätsel zu lösen, wie sie genau ablaufen. Es ist möglich, dass Sie sich entscheiden, keine Fehler zu beheben, aber die zugrunde liegende Ursache zu kennen, hat immer noch Wert. Ich wette, viele Leute, die mit Geld arbeiten, sind froh, selbst winzige Ungenauigkeiten zu bemerken.
Brian
22

Dezimalstellen werden meistens für Geld verwendet ; Bankrundungen sind bei der Arbeit mit Geld üblich . Oder könnte man sagen.

Es sind hauptsächlich Banker, die den Dezimaltyp benötigen. deshalb macht es "Banker-Rundung"

Bankrunden haben den Vorteil, dass Sie im Durchschnitt das gleiche Ergebnis erzielen, wenn Sie:

  • Runden Sie eine Reihe von „Rechnungszeilen“ ab, bevor Sie sie addieren.
  • oder addieren Sie sie und runden Sie die Summe ab

Das Runden vor dem Addieren sparte in den Tagen vor dem Computer viel Arbeit.

(In Großbritannien, als wir dezimal gingen, beschäftigten sich Banken nicht mit halben Pence, aber viele Jahre lang gab es immer noch eine halbe Pence-Münze und im Laden endeten die Preise oft mit halben Pence - also viele Rundungen)

Ian Ringrose
quelle
8
"Dezimalstellen werden meistens für Geld verwendet" ... und alles andere, was keine ganze Zahl ist.
John Tyree
3
@JohnTyree, Nicht wahr Die meiste Zeit wird ein Double / Float verwendet, wenn es keine Ganzzahl ist. siehe stackoverflow.com/questions/2545567/…
Ian Ringrose
3
Beeindruckend. Lächerlicher Fehler meinerseits. Decmials, ja. Dezimalstellen, nein. Für die Nachwelt stimme ich dem ursprünglichen Gefühl hier zu.
John Tyree
Banker mögen vielleicht die Rundung von Bankern, aber die Buchhalter sind vielleicht keine Fans davon. Sie sagen, dass eine Differenz von 0,005 zu einer Rundung um 0,01 führen sollte, unabhängig davon, ob es sich um eine ungerade oder eine gerade Zahl handelt.
JustAMartin
0

Verwenden Sie eine andere Überladung der Round-Funktion wie folgt:

decimal.Round(2.5m, 0,MidpointRounding.AwayFromZero)

Es wird 3 ausgegeben . Und wenn Sie verwenden

decimal.Round(2.5m, 0,MidpointRounding.ToEven)

Sie werden Bankrundung bekommen.

Omid Sadeghi
quelle
4
Dies beantwortet nicht die Frage, warum Banker's Rounding als Standard gewählt wurde.
Shortstuffsushi