decimal
C#では、デフォルトでの丸めは。を使用していることがわかりますMidpointRounding.ToEven
。これは予想されることであり、C#仕様で規定されています。ただし、次の場合:
- A
decimal dVal
string sFmt
に渡されるとdVal.ToString(sFmt)
、の丸められたバージョンを含む文字列になる形式dVal
decimal.ToString(string)
...を使用して丸められた値を返すことは明らかですMidpointRounding.AwayFromZero
。これは、C#仕様と直接矛盾しているように見えます。
私の質問はこれです:これが事実である正当な理由がありますか?それとも、これは言語の単なる矛盾ですか?
decimal.ToString(string)
以下に、参考のために、値の配列内のすべての値について、さまざまな丸め演算結果と演算結果をコンソールに書き込むコードをいくつか含めましたdecimal
。実際の出力は埋め込まれています。その後、タイプのC#言語仕様セクションから関連する段落を含めましたdecimal
。
サンプルコード:
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();
}
C#言語仕様のセクション4.1.7の段落(「10進型」)(完全な仕様はここ(.doc)で入手してください):
10進数型の値に対する演算の結果は、正確な結果(各演算子に対して定義されたスケールを保持)を計算し、表現に合うように丸めた結果です。結果は、最も近い表現可能な値に丸められ、結果が2つの表現可能な値に等しく近い場合は、最下位桁の位置に偶数がある値に丸められます(これは「バンカーの丸め」と呼ばれます)。ゼロの結果は常に0の符号と0のスケールを持ちます。
彼らがこの段落で考慮していなかったかもしれないことは容易に理解できますToString(string)
が、私はそれがこの説明に当てはまると思う傾向があります。