106

通常、double型またはdecimal型の値の同等性に依存することはできませんが、0が特殊なケースであるかどうか疑問に思っています。

0.00000000000001と0.00000000000002の間の不正確さは理解できますが、0自体は何もないので、混乱させるのはかなり難しいようです。あなたが何も不正確であるならば、それはもう何もありません。

しかし、私はこのトピックについてあまり知らないので、私が言うことはありません。

double x = 0.0;
return (x == 0.0) ? true : false;

それは常に真になりますか?

4

9 に答える 9

122

It is safe to expect that the comparison will return true if and only if the double variable has a value of exactly 0.0 (which in your original code snippet is, of course, the case). This is consistent with the semantics of the == operator. a == b means "a is equal to b".

It is not safe (because it is not correct) to expect that the result of some calculation will be zero in double (or more generally, floating point) arithmetics whenever the result of the same calculation in pure Mathematics is zero. This is because when calculations come into the ground, floating point precision error appears - a concept which does not exist in Real number arithmetics in Mathematics.

于 2009-01-27T22:58:04.253 に答える
53

多くの「等しい」比較を行う必要がある場合は、比較のために .NET 3.5 で小さなヘルパー関数または拡張メソッドを作成することをお勧めします。

public static bool AlmostEquals(this double double1, double double2, double precision)
{
    return (Math.Abs(double1 - double2) <= precision);
}

これは次のように使用できます。

double d1 = 10.0 * .1;
bool equals = d1.AlmostEquals(0.0, 0.0000001);
于 2009-01-27T23:06:54.110 に答える
15

単純なサンプルの場合、そのテストは問題ありません。しかし、これはどうですか?

bool b = ( 10.0 * .1 - 1.0 == 0.0 );

.1は2進数の循環小数であり、正確に表すことはできません。これは、1/3を基数10の小数として書き込もうとするのと同じです。次に、それをこのコードと比較します。

double d1 = 10.0 * .1; // make sure the compiler hasn't optimized the .1 issue away
bool b = ( d1 - 1.0 == 0.0 );

実際の結果を確認するためにテストを実行するように任せます。そのように覚えている可能性が高くなります。

于 2009-01-27T20:58:16.633 に答える
14

Double.Equalsの MSDN エントリから:

比較の精度

Equals メソッドは注意して使用する必要があります。これは、2 つの値の精度が異なるため、2 つの明らかに同等の値が等しくない場合があるためです。次の例では、Double 値 .3333 と、1 を 3 で除算して返される Double が等しくないことを報告しています。

...

同等性を比較するのではなく、推奨される手法の 1 つは、2 つの値の間の許容差のマージンを定義することです (値の 0.01% など)。2 つの値の差の絶対値がそのマージン以下である場合、その差は精度の差によるものである可能性が高く、したがって、値が等しい可能性があります。次の例では、この手法を使用して、前のコード例で等しくないことが判明した 2 つの Double 値である .33333 と 1/3 を比較しています。

Double.Epsilonも参照してください。

于 2009-01-27T20:56:03.360 に答える
6

float と double を比較するなど、さまざまなタイプの浮動小数点値の実装を比較するときに問題が発生します。でも同じタイプなら問題ないです。

float f = 0.1F;
bool b1 = (f == 0.1); //returns false
bool b2 = (f == 0.1F); //returns true

問題は、プログラマーが、比較のために暗黙的な型キャスト (double から float) が行われていることを忘れることがあり、バグが発生することです。

于 2011-09-08T12:55:34.513 に答える
3

数値が float または double に直接割り当てられている場合は、ゼロまたは double の場合は 53 ビット、float の場合は 24 ビットで表現できる任意の整数に対してテストしても安全です。

または、別の言い方をすれば、いつでも整数値を double に割り当ててから、double を同じ整数と比較して、等しいことを保証できます。

また、整数を割り当てることから始めて、整数による加算、減算、または乗算に固執することにより、単純な比較を引き続き機能させることもできます (結果が float の場合は 24 ビット未満、double の場合は 53 ビットであると仮定します)。したがって、特定の制御された条件下では、float と double を整数として扱うことができます。

于 2009-01-27T22:07:08.943 に答える
2

いいえ、大丈夫ではありません。いわゆる非正規化された値 (サブノーマル) は、0.0 と比較すると偽 (非ゼロ) として比較されますが、方程式で使用すると正規化されます (0.0 になります)。したがって、これをゼロ除算を回避するメカニズムとして使用することは安全ではありません。代わりに、1.0 を追加して 1.0 と比較します。これにより、すべてのサブノーマルがゼロとして扱われるようになります。

于 2009-04-10T15:27:05.287 に答える
-5

実際には、次のコードを使用して double 値を 0.0 と比較する方が良いと思います。

double x = 0.0;
return (Math.Abs(x) < double.Epsilon) ? true : false;

フロートについても同じ:

float x = 0.0f;
return (Math.Abs(x) < float.Epsilon) ? true : false;
于 2011-12-15T17:22:24.450 に答える