Frage

Nach der Dokumentation, die decimal.Round Methode verwendet ein rund- to-even-Algorithmus, der für die meisten Anwendungen nicht üblich ist. Also ich am Ende immer eine benutzerdefinierte Funktion zu schreiben, die mehr natürlichen runden Halb-up-Algorithmus zu tun:

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;
}

Weiß jemand, den Grund hinter diesem Rahmen Design-Entscheidung?

Gibt es eine eingebaute in Umsetzung des Rundhalb-up-Algorithmus in den Rahmen? Oder vielleicht einige nicht verwaltete Windows-API?

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

War es hilfreich?

Lösung

Wahrscheinlich, weil es ist ein besserer Algorithmus. Im Laufe vieler Abrundungen durchgeführt wird, wird im Durchschnitt Sie darauf hin, dass alle am Ende des 0,5 bis Rundung gleich nach oben und unten. Dies ergibt eine bessere Schätzungen der tatsächlichen Ergebnisse, wenn Sie zum Beispiel sind, eine Reihe von gerundeten Zahlen addieren. Ich würde sagen, dass, obwohl es nicht das, was erwarten einige können, ist es wahrscheinlich die richtigere, was zu tun.

Andere Tipps

Die anderen Antworten mit Gründe, warum die Banker-Algorithmus (aka rund die Hälfte sogar ) ist eine gute Wahl ganz richtig ist. Es leidet nicht an negativen oder positiven Vorspannung so viel wie der rund die Hälfte weg von Null Verfahren über vernünftigste Distributionen.

Aber die Frage war, warum .NET Bankers tatsächliche Runden als Standard verwenden - und die Antwort ist, dass Microsoft den IEEE 754 Standard. Dies spiegelt sich auch in MSDN erwähnt für Math.Round unter Bemerkungen.

Beachten Sie auch, dass .NET die alternative Methode der Norm IEEE unterstützt durch die MidpointRounding Aufzählung bereitstellt. Sie könnten natürlich haben mehr Alternativen Bindungen zu lösen, sondern sie wählen, um nur erfüllen den IEEE-Standard.

Auch wenn ich nicht die Frage beantworten können „Warum hat Microsoft die Designer wählen diese als Standard?“, Ich möchte nur darauf hinweisen, dass eine zusätzliche Funktion nicht erforderlich ist.

Math.Round ermöglicht es Ihnen, ein MidpointRounding :

  • Toeven -. Wenn eine Zahl auf halbem Weg zwischen zwei anderen ist, wird sie in Richtung auf die nächste gerade Zahl gerundet
  • AwayFromZero - Wenn eine Zahl auf halbem Weg zwischen zwei anderen ist, wird sie in Richtung auf die nächste Zahl gerundet, die von Null weg.

Dezimalzahlen sind meist verwendet für Geld ; bankübliche Rundung ist üblich, wenn mit Geld zu arbeiten. Oder man könnte sagen.

  

Es ist vor allem Banker, dass die Notwendigkeit   decimal Typ; deshalb tut es   „Bankübliche Rundung“

Bankers Runden hat den Vorteil, dass im Durchschnitt das gleiche Ergebnis erhalten, wenn Sie:

  • um eine Reihe von „Rechnungsposten“ vor dem Hinzufügen von ihnen,
  • oder sie addieren sich dann um die gesamte

Rounding vor dem Hinzufügen sparte eine Menge Arbeit in den Tagen vor dem Computer.

(in Großbritannien, wenn wir dezimal Banken gingen nicht mit halben Pence beschäftigen würde, aber seit vielen Jahren gab es noch eine halbe Pence-Münze und Shop Preise oft hatte in Hälfte Pence enden - so viele Runden)

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

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

Es wird ausgegeben 3 . Und wenn Sie mit

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

Sie werden bankübliche Rundung erhalten.

Beachten Sie auch, dass über einen Format-String (zB "0") "Abrunden" erzeugt ein anderes Ergebnis als "Math.Round ()". Das heißt, dass 5, 0,5, etc .. wird immer aufgerundet wird:

let d, d' = 2.5, 3.5

Debug.WriteLine(Math.Round(d))      // 2.5 -> 2
Debug.WriteLine(d.ToString("0"))    // 2.5 -> 3

Debug.WriteLine(Math.Round(d'))     // 3.5 -> 4
Debug.WriteLine(d'.ToString("0"))   // 3.5 -> 4


let dd, dd' = 2.25, 2.35

Debug.WriteLine(Math.Round(dd, 1))     // 2.25 -> 2.2
Debug.WriteLine(dd.ToString("0.0"))    // 2.25 -> 2.3

Debug.WriteLine(Math.Round(dd', 1))    // 2.35 -> 2.4
Debug.WriteLine(dd'.ToString("0.0"))   // 2.35 -> 2.4
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top