C#のMath.Roundメソッド:四捨五入と「銀行家の丸め」(ToEven)の重要な違い

目次

C#における数値の「丸め」

C#でdoubledecimalといった小数点以下の数値を持つデータを扱う際、計算結果を指定した桁数に「丸める」処理は不可欠です。一般的に「四捨五入」と呼ばれる処理ですが、C#の標準メソッドであるMath.Roundは、デフォルトの動作が一般的な四捨五入とは異なるため、注意が必要です。

この記事では、Math.Roundメソッドの基本的な使い方と、丸め処理の規則を制御するMidpointRoundingについて詳しく解説します。


Math.Round の基本的な使い方

Math.Roundメソッドには、主に以下のオーバーロード(引数の形式)があります。

  • Math.Round(value): 値を整数(小数点以下0桁)に丸めます。
  • Math.Round(value, digits): 値を指定したdigits(桁数)に丸めます。
  • Math.Round(value, digits, mode): 値を指定した桁数に、mode(丸め規則)で丸めます。

デフォルトの動作:「銀行家の丸め」 (MidpointRounding.ToEven)

Math.Roundメソッドで丸め規則(mode)を省略した場合、デフォルトで MidpointRounding.ToEven(最近接偶数への丸め)、通称「銀行家の丸め」が適用されます。

これは、丸める桁の数値がちょうど.5(中間点)であった場合に、丸めた結果が偶数になる方向へ丸める規則です。

  • Math.Round(12.5) の結果は 12 になります(12が偶数)。
  • Math.Round(13.5) の結果は 14 になります(14が偶数)。

この方法は、大量のデータを集計する際に、.5を常に切り上げることによって生じる統計的な偏り(バイアス)を最小限に抑えるために、科学技術計算や金融分野で標準的に用いられます。

ToEven(デフォルト)のコード例

小数点第2位に丸める(digits = 2)場合の例です。

using System;

public class ToEvenRoundingExample
{
    public static void Main()
    {
        // 銀行家の丸め (デフォルト)
        decimal value1 = 10.125m; // 中間点 (.005)
        decimal value2 = 10.135m; // 中間点 (.005)

        // value1: .125 -> 10.12 (12は偶数)
        decimal result1 = Math.Round(value1, 2); 
        
        // value2: .135 -> 10.14 (14は偶数)
        decimal result2 = Math.Round(value2, 2);

        Console.WriteLine($"--- 銀行家の丸め (ToEven) ---");
        Console.WriteLine($"{value1} -> {result1}");
        Console.WriteLine($"{value2} -> {result2}");
    }
}

出力結果:

--- 銀行家の丸め (ToEven) ---
10.125 -> 10.12
10.135 -> 10.14

一般的な「四捨五入」:MidpointRounding.AwayFromZero

もし、いわゆる「四捨五入」(.5の場合は常に切り上げる)を行いたい場合は、Math.Roundの第3引数に MidpointRounding.AwayFromZero を明示的に指定する必要があります。

このモードは、中間点(.5)の場合、0(ゼロ)から遠ざかる方向に丸めます。

  • 12.513 になります(0から遠ざかる)。
  • 13.514 になります(0から遠ざかる)。
  • -12.5-13 になります(0から遠ざかる)。

AwayFromZero のコード例

using System;

public class AwayFromZeroRoundingExample
{
    public static void Main()
    {
        // 四捨五入
        decimal value1 = 10.125m; // 中間点 (.005)
        decimal value2 = 10.135m; // 中間点 (.005)
        decimal value3 = -10.125m; // 負の中間点

        // value1: .125 -> 10.13 (切り上げ)
        decimal result1 = Math.Round(value1, 2, MidpointRounding.AwayFromZero); 
        
        // value2: .135 -> 10.14 (切り上げ)
        decimal result2 = Math.Round(value2, 2, MidpointRounding.AwayFromZero);
        
        // value3: -10.125 -> -10.13 (0から遠ざかる方向へ)
        decimal result3 = Math.Round(value3, 2, MidpointRounding.AwayFromZero);

        Console.WriteLine($"--- 四捨五入 (AwayFromZero) ---");
        Console.WriteLine($"{value1} -> {result1}");
        Console.WriteLine($"{value2} -> {result2}");
        Console.WriteLine($"{value3} -> {result3}");
    }
}

出力結果:

--- 四捨五入 (AwayFromZero) ---
10.125 -> 10.13
10.135 -> 10.14
-10.125 -> -10.13

2つのモードの比較

以下のコードは、複数の値に対して2つの丸め規則を適用した結果を比較します。

using System;

public class RoundingComparison
{
    public static void Main()
    {
        // 比較対象の数値配列
        var valuesToRound = new double[] { 4.12, 4.15, 4.25, 4.18 };
        int digits = 1; // 小数点第1位に丸める

        Console.WriteLine("元の値 | AwayFromZero (四捨五入) | ToEven (銀行家の丸め)");
        Console.WriteLine("-----------------------------------------------------");

        foreach (var val in valuesToRound)
        {
            var roundAway = Math.Round(val, digits, MidpointRounding.AwayFromZero);
            var roundEven = Math.Round(val, digits, MidpointRounding.ToEven);

            Console.WriteLine($"{val:F2}   | {roundAway:F1}                   | {roundEven:F1}");
        }
    }
}

出力結果:

元の値 | AwayFromZero (四捨五入) | ToEven (銀行家の丸め)
-----------------------------------------------------
4.12   | 4.1                   | 4.1
4.15   | 4.2                   | 4.2
4.25   | 4.3                   | 4.2
4.18   | 4.2                   | 4.2

4.15(中間点)はAwayFromZeroでは4.2ToEvenでも(結果が偶数のため)4.2になります。 4.25(中間点)はAwayFromZeroでは4.3になりますが、ToEvenでは(結果が偶数になるよう)4.2になります。


まとめ

C#のMath.Roundは強力な丸めメソッドですが、そのデフォルト動作はMidpointRounding.ToEven(銀行家の丸め)であり、一般的な「四捨五入」とは異なります。

  • 銀行家の丸め(統計的な偏りが少ない)が必要な場合: Math.Round(value, digits) (デフォルト)を使用します。
  • 一般的な四捨五入(.5は常に0から遠ざかる)が必要な場合: Math.Round(value, digits, MidpointRounding.AwayFromZero) を明示的に指定します。

計算要件に応じて、正しい丸めモードを選択することが非常に重要です。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次