6

Visual Studio Professional 2012 を使用しています。次のコードを使用して、.NET Framework 4.5 をターゲットとする新しい C# ConsoleApplication を作成しました。

    static void Main(string[] args)
    {
        double x = 2.44445;
        double y = Math.Round(x, 4, MidpointRounding.AwayFromZero);
        Console.WriteLine(y);
        Console.ReadKey();
    }

期待される結果は 2.4445 のはずですが、実際には 2.4444 が返されます。//以前のフレームワーク バージョンでも同じ結果で、VCE2010 を試しました。

このような問題は通常、double データ型の格納方法 (つまり、有限の 10 進数が無限の 2 進数に変換される) に起因することを知っています。しかし、2.44445 のように 5 桁の 10 進数でこれが起こるとは思っていませんでした

もっと短い小数でもそうならないか心配です。また、C# で (ゼロから離れた規則を使用して) 丸めるためのより安全な方法を学びたいと思います。ありがとう。

4

2 に答える 2

11

これは確かに、浮動小数点数の精度が壊れやすいためです。0.5はIEEE浮動小数点に完全に格納できますが、0.45、0.445などは格納できません。たとえば、2.44445を指定したときに保存される実際の値は、11009049289107177/4503599627370496であり、2.44449999999999989519494647です。これで、数値がこのように丸められる理由が明らかになります。

小数を正確に格納する必要がある場合は、decimal代わりに型を使用することを検討してください。

于 2012-12-27T13:45:09.787 に答える
4

msdnからのメモ

10進値を浮動小数点数として表すか、浮動小数点値に対して算術演算を実行すると精度が低下するため、場合によっては、Round(Double、Int32、MidpointRounding)メソッドが指定されたとおりに中点値を丸めないように見えることがあります。モードパラメータによって。これを次の例に示します。ここでは、2.135が2.14ではなく2.13に丸められています。これは、メソッドが内部的に値を10桁で乗算するために発生し、この場合の乗算演算では精度が低下します。

Roundの実装方法は次のとおりです。

double num = roundPower10Double[digits];
value *= num;
if (mode == MidpointRounding.AwayFromZero)
{
    double num2 = SplitFractionDouble(&value);
    if (Abs(num2) >= 0.5)
    {
        value += Sign(num2);
    }
}

ご覧のとおり、値はnumで乗算されます。これは、

roundPower10Double = new double[] { 1.0, 10.0, 100.0, 1000.0, 10000.0, 
      100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0, 10000000000,  
      100000000000, 1000000000000, 10000000000000, 100000000000000, 1E+15 };    

だから、実際にはあなたは2.44445 * 10000.0 - 24444,0それを与えるものを持っています0,499999999996362。未満です0.5。したがって、あなたは持ってい2.4444ます。

于 2012-12-27T13:46:59.710 に答える