Ich sehe, dass in C#, Rundung decimal
, standardmäßig verwendet MidpointRounding.ToEven
. Dies ist zu erwarten und genau das, was die C# -Spezifikation vorschreibt. Angesichts der folgenden:Warum wird .NET decimal.ToString (string) von Null weggerundet, scheinbar inkonsistent mit der Sprachspezifikation?
- A
decimal dVal
- Ein Format
string sFmt
die, wenn sie in zudVal.ToString(sFmt)
weitergegeben, in einem String führt eine abgerundete Version vondVal
enthält, ... es ist offensichtlich, dass decimal.ToString(string)
einen Wert zurückgibt, der mit MidpointRounding.AwayFromZero
gerundet wurde. Dies scheint ein direkter Widerspruch zu der C# -Spezifikation zu sein.
Meine Frage ist dies: gibt es einen guten Grund, dass dies der Fall ist? Oder ist das nur eine Inkonsistenz in der Sprache?
Unten, als Referenz, habe ich einige Code enthalten, der eine Reihe von Rundungsoperation Ergebnisse und decimal.ToString(string)
Betriebsergebnisse, jeder auf jedem Wert in einem Array von decimal
Werte zu Konsole Konsolen schreibt. Die tatsächlichen Ausgaben sind eingebettet. Danach habe ich einen relevanten Absatz aus dem C# -Sprachspezifikationsabschnitt unter dem Typ decimal
eingefügt.
Der Beispielcode:
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# Language Specification ("Der Dezimal-Typ") (erhalten Sie die vollständige Spezifikation here (.doc)):
Das Ergebnis einer Operation für Werte vom Typ Dezimal ist derjenige, der sich aus der Berechnung eines exakten Ergebnisses ergeben würde (Beibehalten der Skalierung, wie für jeden Operator definiert) und anschließendes Runden, um die Darstellung anzupassen. Die Ergebnisse werden auf den nächsten darstellbaren Wert und, wenn ein Ergebnis gleich zwei darstellbaren Werten entspricht, auf den Wert gerundet, der eine gerade Zahl in der niedrigstwertigen Stellenposition hat (dies wird als "Banker-Rundung" bezeichnet). Ein Null-Ergebnis hat immer ein Vorzeichen von 0 und eine Skala von 0.
Es ist leicht zu sehen, dass sie ToString(string)
in diesem Absatz nicht berücksichtigt haben, aber ich bin geneigt zu denken, dass es in diese Beschreibung passt.
Es ist möglich, dass Sie berücksichtigen sollten, dass C# keine 'ToString (string)' Methode hat. Das .NET Framework funktioniert. Ich bin mir nicht sicher, ob das .NET Framework den Regeln einer bestimmten Programmiersprache unterliegt. –