5

Brainteasersからこのコードをテストしていました。

        double d1 = 1.000001;

        double d2 = 0.000001;

        Console.WriteLine((d1 - d2) == 1.0);

そして結果は「偽」です。データ型を変更すると:

        decimal d1 = 1.000001M;

        decimal d2 = 0.000001M;

        decimal d3 = d1-d2;

        Console.WriteLine(d3 == 1);

プログラムは、正解「True」を書き込みます。

この問題は、浮動小数点の後に 6 桁を使用するだけです。15桁の精度で何が起こったのですか?

4

6 に答える 6

28

これは精度とは関係ありません。表現上の丸め誤差と関係があります。

System.Decimalは、表示されているような丸めエラーが発生するリスクを大幅に減らしながら、大きな浮動小数点数を表すことができます。 System.Singleこれができず、 System.Doubleこれらの数値を四捨五入して、例で見ているような問題を引き起こします。

System.Decimalスケーリング係数を使用して小数点以下の位置を保持するため、指定された浮動小数点数を正確に表現できますが、可能なSystem.Single限り System.Double値を近似するだけです。

詳細については、次を参照してくださいSystem.Double

浮動小数点数は 10 進数しか近似できないこと、および浮動小数点数の精度によって、その数値が 10 進数をどれだけ正確に近似できるかが決まることに注意してください。デフォルトでは、Double 値には 10 進数で 15 桁の精度が含まれますが、内部では最大 17 桁が保持されます。浮動小数点数の精度には、いくつかの結果があります。

  • 特定の精度では同じように見える 2 つの浮動小数点数は、最下位桁が異なるため、等しくない場合があります。

  • 浮動小数点数が 10 進数を正確に近似していない可能性があるため、10 進数が使用されている場合、浮動小数点数を使用する数学演算または比較演算で同じ結果が得られない場合があります。

于 2009-09-08T18:55:34.143 に答える
8

一般に、浮動小数点値が等しいかどうかを確認する方法は、ほぼ等しいかどうかを確認することです。つまり、そのデータ型の最小値(イプシロンと呼ばれる)に近い差を確認します。例えば、

if (Math.Abs(d1 - d2) <= Double.Epsilon) ...

d1これは、とが同じビットパターンで表されているかどうかをテストしてd2、最下位ビットを生成または取得します。

訂正 (2015年3月2日追加)

さらに詳しく調べると、コードは次のようになります。

// Assumes that d1 and d2 are not both zero
if (Math.Abs(d1 - d2) / Math.Max(Math.Abs(d1), Math.Abs(d2)) <= Double.Epsilon) ...

つまり、との絶対差を取り、d1とのd2最大値でスケーリングしてからと比較します。d1d2Epsilon

参照
• http: //msdn.microsoft.com/en-us/library/system.double.epsilon.aspx•http
//msdn.microsoft.com/en-us/library/system.double.aspx#Precision

于 2009-09-08T19:22:52.967 に答える
6

The decimal type implements decimal floating point whereas double is binary floating point.

The advantage of decimal is that it behaves as a human would with respect to rounding, and if you initialise it with a decimal value, then that value is stored precisely as you specified. This is only true for decimal numbers of finite length and within the representable range and precision. If you initialised it with say 1.0M/3.0M, then it would not be stored precisely just as you would write 0.33333-recurring on paper.

If you initialise a binary FP value with a decimal, it will be converted from the human readable decimal form, to a binary representation that will seldom be precisely the same value.

The primary purpose of the decimal type is for implementing financial applications, in the .NET implementation it also has a far higher precision than double, however binary FP is directly supported by the hardware so is significantly faster than decimal FP operations.

Note that double is accurate to approximately 15 significant digits not 15 decimal places. d1 is initialised with a 7 significant digit value not 6, while d2 only has 1 significant digit. The fact that they are of significantly different magnitude does not help either.

于 2009-09-08T19:57:38.107 に答える
3

浮動小数点数の考え方は、特定の桁数に対して正確ではないということです。そのような機能が必要な場合は、decimalデータ型を確認する必要があります。

于 2009-09-08T18:55:42.630 に答える
3

10 進数と 2 進数を正確に変換することはできないため、精度は絶対的なものではありません。

この場合、2 進数で表すと、10 進数の .1 が永遠に繰り返されます。.000110011001100110011... に変換され、永遠に繰り返されます。それを正確に保存する精度はありません。

于 2009-09-08T19:11:20.260 に答える
2

浮動小数点数の等価性の比較を避けます。

于 2009-09-08T19:07:01.563 に答える