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 übergebendVal.ToString(sFmt)
" wird eine Zeichenfolge, die eine abgerundete versiondVal
...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.
Du musst angemeldet sein, um einen Kommentar abzugeben.
ToString()
von Standard-Formaten nach denCulture
, nicht nach einer computational Aspekt der Spezifikation. Anscheinend ist derCulture
für Ihr Gebietsschema (und die meisten, von den blicken von ihm) erwartet, dass die Rundung Weg von der null.Wenn Sie wollen, Verhalten sich anders, Sie können gehen einIFormatProvider
inToString()
Dachte ich, die oben genannten, aber Sie sind richtig, dass es immer Runden Weg von null, egal die
Culture
. Überprüfen Sie die links in den Kommentaren für den Nachweis.Wenn Sie Lesen, die spec sorgfältig, Sie werden sehen, dass es keine Inkonsistenz hier.
Hier ist, dass der Absatz wieder, mit der wichtigen Teile hervorgehoben:
Diesem Teil der Spezifikation gilt für arithmetische Operationen auf
decimal
; string Formatierung ist nicht einer von denen, und selbst wenn es so wäre, wäre es egal, weil deine Beispiele sind geringer Präzision.Nachweisen, die das Verhalten gemäß der Spezifikation, verwenden Sie den folgenden code:
Dass alle die Skillung spricht. Wenn das Ergebnis einer Berechnung überschreitet die Präzision Grenze des
decimal
Typ (29 stellen), für die bankübliche Rundung wird verwendet, um zu bestimmen, was das Ergebnis sein wird.Wahrscheinlich, denn dies ist die standard-Art des Umgangs mit der Währung. Den Anstoß zur Bildung von dezimalen war, dass floating point macht einen schlechten job für den Umgang mit Währung Werte, so würden Sie erwarten, dass es Regeln zu mehr Einklang mit den Rechnungslegungsstandards als mathematische Richtigkeit.