2012-02-29 7 views
0
でダブルス結果を丸め

可能性の重複:
Why is floating point arithmetic in C# imprecise?の保存は非直感的な結果

もし私の数多くのランダムダブルスをループし、2つの端数桁の場所にそれらを「ラウンド」、各個々のラウンドが正しいように見えます(0.02,0.01、0.00など)。

しかし、ラウンドに沿って保持される非常に小さな部分があるように見えます。

double total = 0; 

for (int i = 0; i < 10000; i++) 
{ 
    total += Math.Round(random.NextDouble() * 0.02, 2); 
} 

Console.WriteLine(total); 

サンプル出力:

100.600000000006

99.7400000000059

誰でもこの問題が発生した理由を説明する気にはより直感的な方法は何ですか?

答えて

4

System.DoubleとSystem.Floatは基本2浮動小数点型です。このような値に丸めると、バイナリ表現はおおよその値になります。この問題を回避するには、基数10の浮動小数点型のdecimal型を使用します。

stackoverflowでこの質問は100回重複している必要がありますが、私は自分の携帯電話にいるため、それらを見つけてリンクするのが面倒です。

詳細については、IEEE doubleのwikipediaの記事を参照してください。

多くの人が、ダブルスは「正確ではない」と言っていますが、これは誤りです。すべてのdouble値は、基数10で正確に表すことができる正確な値を表します(NaNと無限大を除く)。これは、2が10の素因数の1つであるためです。唯一の近似は、特定の小数部分(または分母に2以外の少なくとも1つの素因数を持つ他の有理数)を表現しようとするときです。

これを理解する最善の方法は、少なくとも私にとっては、いくつかの分数のバイナリ表現を紙面で調べることです。たとえば、0.5,0.625,3.25,5/16,1/3,0.2、および0.3を試してください。

0

倍精度浮動小数点数は、基数10の数値を格納しません。つまり、基数2に値を格納するため、分数を格納するときに期待される小数点の値との小さな差異を示すことができます。それは価値があるため、ベース2に固有のものではありません。ベース10(実際にはすべてのベースNシステム)にも同じ問題があります。たとえば、1/3です。ベース10では、これを0.3333333(...)のように表現することになりますが、ベース10の1/3を完全に表す方法はありません。

この例では、数字の小数部分、これらを一緒に追加するため、これらの小さなエラーが蓄積することがあります。上記の例を使用して、.333333(...)を小数点以下第2位に丸めると、0.33が得られますが、実際の1/3の値に対してかなりの不正確さがあります。これらの不正確さを累積することは、浮動小数点演算を行う際のよくある間違いです。

@Phoogが書いているように、これについては多くの説明があります。ここには1つがあります。Why is floating point arithmetic in C# imprecise?

+3

ダブルスは*極めて正確な数字で、*正確な数字を格納します。その数値は、基数2に格納されるため、数値を基数10に格納すると予想される場合にのみエラーになります。 –

+0

@EricLippertは同意しました。私はこれを急いで書いたので、もっと明確に説明してください。 –

+0

それに応じて編集してください。より正確な答えです。 –

関連する問題