5

コード内で、丸められた値が間違って計算されるメソッドを偶然見つけました。double 値を比較すると予期しない結果が生成されるという問題について認識しています。

    double x = 19.08;
    double y = 2.01;
    double result = 21.09;

    if (x + y == result)
    {
        // this is never reached
    }

ここでの説明: http://csharpindepth.com/Articles/General/FloatingPoint.aspx

ただし、これまでは、Math.Round() メソッドは double 値でも正確であると思っていました。

このコードを見てください。

        var decimals = 2;
        var value1 = 4.725;
        var value2 = 4.725M;

        var result1 = Math.Round(value1, decimals, MidpointRounding.ToEven);
        var result2 = Math.Round(value1, decimals, MidpointRounding.AwayFromZero);
        var result3 = Math.Round(value2, decimals, MidpointRounding.ToEven);
        var result4 = Math.Round(value2, decimals, MidpointRounding.AwayFromZero);

        Console.WriteLine("Double (ToEven): {0}", result1); // outputs 4.72
        Console.WriteLine("Double (AwayFromZero): {0}", result2); // outputs 4.72 (expected: 4.73)
        Console.WriteLine("Decimal (ToEven): {0}", result3); // outputs 4.72
        Console.WriteLine("Decimal (AwayFromZero): {0}", result4); // outputs 4.73

私にとって、result2 が 4.73 であることは明らかです。しかし、そうではありません。誰かが理由を説明できますか?

4

4 に答える 4

10

4.725 (4.625 とは対照的に)double. 実はまさに

4.7249999999999996447286321199499070644378662109375

浮動小数点数は、実数の数学的概念の近似値にすぎないことに注意してください。数値がどのように動作するかについての直感的な概念の多くは当てはまりません。最終的には4.725 の値になりますが、明らかにわずかに下回っています。したがって、中点丸めモードは、丸められる 2 つの数値のちょうど中間ではないため、ここでは何もしません。

于 2012-08-28T11:17:47.740 に答える
1

あなたvalue1は簡単にできます4.7249999999999999999999999999999994.73ではなく に丸める必要があるのはなぜ4.72ですか?

于 2012-08-28T11:17:38.597 に答える
0

Double 値との等価性をチェックする場合、常に問題が発生します。0.5 + 0.5 のような 2 つの double 値を追加しても 1.0 にはなりませんが、最終的には 0.99999 と 1.00001 のようになる可能性が高くなります。これは、浮動小数点数を使用した 2 進数から 10 進数への変換に関係しています。

丸め誤差/精度セクションで次の読み取りを確認する必要があります : http://www.learncpp.com/cpp-tutorial/25-floating-point-numbers/ C# の場合も同様です。

于 2012-08-28T11:19:05.450 に答える
0

Math.Round(value1, 2) の代わりに Convert.ToDouble(value1.ToString("f2")) を使用します

于 2014-08-21T09:28:50.430 に答える