Warum nicht .NETTO Dezimalstellen.ToString(string) - Runde Weg von null, anscheinend unvereinbar mit der Sprache Skillung?

Sehe ich, dass in C#, Rundung eine decimal verwendet standardmäßig MidpointRounding.ToEven. Dies ist zu erwarten und ist das, was die C# - Spezifikation vorschreibt. Angesichts der folgenden:

  • Eine decimal dVal
  • Ein format string sFmt dass, wenn übergeben dVal.ToString(sFmt) " wird eine Zeichenfolge, die eine abgerundete version dVal

...es ist offensichtlich, dass decimal.ToString(string) gibt einen Wert zurück, abgerundet mit MidpointRounding.AwayFromZero. Dies scheint ein direkter Widerspruch zu der C# - spec.

Meine Frage ist: gibt es einen guten Grund, warum dies der Fall ist? Oder ist dies nur eine Ungenauigkeit in der Sprache?

Unten, als Referenz, ich habe einige code, der schreibt in die Konsole ein Sortiment von rundungsoperation Ergebnisse und decimal.ToString(string) Betrieb Ergebnisse, auf jeder Wert in einem array von decimal Werte. Die tatsächlichen Ausgaben eingebettet sind. Danach habe ich einen entsprechenden Abschnitt aus der C# Language Specification Abschnitt auf der decimal geben.

Den Beispiel-code:

static void Main(string[] args)
{
    decimal[] dArr = new decimal[] { 12.345m, 12.355m };

    OutputBaseValues(dArr);
    //Base values:
    //d[0] = 12.345
    //d[1] = 12.355

    OutputRoundedValues(dArr);
    //Rounding with default MidpointRounding:
    //Math.Round(12.345, 2) => 12.34
    //Math.Round(12.355, 2) => 12.36
    //decimal.Round(12.345, 2) => 12.34
    //decimal.Round(12.355, 2) => 12.36

    OutputRoundedValues(dArr, MidpointRounding.ToEven);
    //Rounding with mr = MidpointRounding.ToEven:
    //Math.Round(12.345, 2, mr) => 12.34
    //Math.Round(12.355, 2, mr) => 12.36
    //decimal.Round(12.345, 2, mr) => 12.34
    //decimal.Round(12.355, 2, mr) => 12.36

    OutputRoundedValues(dArr, MidpointRounding.AwayFromZero);
    //Rounding with mr = MidpointRounding.AwayFromZero:
    //Math.Round(12.345, 2, mr) => 12.35
    //Math.Round(12.355, 2, mr) => 12.36
    //decimal.Round(12.345, 2, mr) => 12.35
    //decimal.Round(12.355, 2, mr) => 12.36

    OutputToStringFormatted(dArr, "N2");
    //decimal.ToString("N2"):
    //12.345.ToString("N2") => 12.35
    //12.355.ToString("N2") => 12.36

    OutputToStringFormatted(dArr, "F2");
    //decimal.ToString("F2"):
    //12.345.ToString("F2") => 12.35
    //12.355.ToString("F2") => 12.36

    OutputToStringFormatted(dArr, "###.##");
    //decimal.ToString("###.##"):
    //12.345.ToString("###.##") => 12.35
    //12.355.ToString("###.##") => 12.36

    Console.ReadKey();
}

private static void OutputBaseValues(decimal[] dArr)
{
    Console.WriteLine("Base values:");
    for (int i = 0; i < dArr.Length; i++) Console.WriteLine("d[{0}] = {1}", i, dArr[i]);
    Console.WriteLine();
}

private static void OutputRoundedValues(decimal[] dArr)
{
    Console.WriteLine("Rounding with default MidpointRounding:");
    foreach (decimal d in dArr) Console.WriteLine("Math.Round({0}, 2) => {1}", d, Math.Round(d, 2));
    foreach (decimal d in dArr) Console.WriteLine("decimal.Round({0}, 2) => {1}", d, decimal.Round(d, 2));
    Console.WriteLine();
}

private static void OutputRoundedValues(decimal[] dArr, MidpointRounding mr)
{
    Console.WriteLine("Rounding with mr = MidpointRounding.{0}:", mr);
    foreach (decimal d in dArr) Console.WriteLine("Math.Round({0}, 2, mr) => {1}", d, Math.Round(d, 2, mr));
    foreach (decimal d in dArr) Console.WriteLine("decimal.Round({0}, 2, mr) => {1}", d, decimal.Round(d, 2, mr));
    Console.WriteLine();
}

private static void OutputToStringFormatted(decimal[] dArr, string format)
{
    Console.WriteLine("decimal.ToString(\"{0}\"):", format);
    foreach (decimal d in dArr) Console.WriteLine("{0}.ToString(\"{1}\") => {2}", d, format, d.ToString(format));
    Console.WriteLine();
}


Der Absatz von Abschnitt 4.1.7 der C# - Sprachspezifikation ("Der Typ decimal") (die vollständige Spezifikation hier (.doc)):

Das Ergebnis einer operation auf Werte vom Typ "decimal" ist, dass die sich aus der Berechnung ein exaktes Ergebnis (Erhaltung der Skala, für die einzelnen Betreiber) und dann die Rundung passen Sie die Darstellung. Ergebnisse sind gerundet auf den nächsten darstellbaren Wert, und, wenn ein Ergebnis ist gleich in der Nähe von zwei darstellbaren Werten, dem Wert, der eine gerade Anzahl in der niederwertigsten Stelle (dies ist bekannt als "banker' s rounding"). Ein null-Resultat immer ein Zeichen von 0 und einer Skala, die von 0.

Es ist leicht zu sehen, dass Sie möglicherweise nicht in Betracht gezogen haben ToString(string) in diesem Absatz, aber ich bin geneigt zu denken, es passt in diese Beschreibung.

  • Es ist möglich, dass Sie sollten Bedenken, dass C# keine ToString(string) Methode. Die .NET Framework nicht. Ich bin mir nicht sicher, dass die .NET-Framework gebunden ist, zu gehorchen den Regeln einer bestimmten Programmiersprache.
InformationsquelleAutor stack | 2010-02-12
Schreibe einen Kommentar