浮動小数点値が 0 に等しいかどうかを確認しても安全ですか?
-
20-08-2019 - |
質問
通常、double 型または 10 進型の値の間の等価性を信頼できないことはわかっていますが、0 が特殊な場合なのかどうか疑問に思っています。
0.00000000000001 と 0.00000000000002 の間の不精度は理解できますが、0 自体は何もないので、混乱させるのはかなり難しいようです。何もかも不正確であれば、それはもはや何もではありません。
しかし、私はこの件についてはあまり詳しくないので、言うべきことではありません。
double x = 0.0;
return (x == 0.0) ? true : false;
それは常に true を返すのでしょうか?
解決
これは安全なの をダブル変数が値を持っている場合にだけ比較はtrue
返すことを期待する正確0.0
(元のコードスニペットである、もちろん、ケース)。これは==
演算子の意味と一致しています。 a == b
手段 "a
b
に等しい。"
これは、算術演算(それはの正しくないのため)いくつかの計算の結果は、二重(またはより一般的に浮動小数点)でゼロになることを期待するの安全でないのでありますたびに純粋数学同じ演算結果がゼロです。計算は小数点精度エラーが表示され、フローティング、地面に来たときにこれがある - 。数学の実数算術演算に存在しない概念を
他のヒント
比較のために、.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);
あなたの簡単なサンプルについては、そのテストは大丈夫です。しかし、このことについて何ます:
bool b = ( 10.0 * .1 - 1.0 == 0.0 );
0.1がバイナリで循環小数であると正確に表現できないことに注意してください。そして、このコードにそれを比較します:
double d1 = 10.0 * .1; // make sure the compiler hasn't optimized the .1 issue away
bool b = ( d1 - 1.0 == 0.0 );
私は、実際の結果を確認するためにテストを実行するためにあなたを残しておきます:あなたがそのように覚えている可能性が高くなります。
。MSDN エントリより Double.Equals:
比較の精度
2つの値の精度が異なるため、2つの明らかに同等の値が不平等になる可能性があるため、等しい方法は注意して使用する必要があります。次の例では、1 x 3を除算することで二重値.3333と二重返されたものは不平等であると報告しています。
...
平等を比較するのではなく、1つの推奨される手法では、2つの値(値の1つの.01%など)の違いの許容可能なマージンを定義することが含まれます。2つの値間の差の絶対値がそのマージン以下である場合、差は精度の違いによるものである可能性が高いため、値は等しい可能性があります。次の例では、この手法を使用して.33333と1/3を比較します。これは、前のコードの例が不均等であると判断した2つの二重値です。
また、を参照してください。 ダブル.イプシロン.
問題が来ますダブルでfloatを比較します。しかし、同じタイプで、それが問題になることはありません。
float f = 0.1F;
bool b1 = (f == 0.1); //returns false
bool b2 = (f == 0.1F); //returns true
問題があり、プログラマは、時々暗黙の型キャスト(doubleからfloatへ)バグに比較し、その結果を得るために起こっていることを忘れています。
数を直接フロートまたは二重に割り当てられた場合、ゼロまたはフロートのための二重または24ビットのために53ビットで表現することができる任意の整数に対してテストしても安全である。
それとも、あなたが常に割り当てて、整数値の二重にしてから、同じ整数にダブルバックを比較し、それが同じになりますが保証されます。
することができ、別の言い方をしますまた、全体の数を割り当てることによって実行を開始することができ、単純な比較は、(結果は二重フロートABD 53ビット未満24ビットであると仮定して)、加算、減算、または整数を乗算に貼り付け作業を継続しています。ですから、特定の制御された条件下での整数として山車とダブルスを扱うことができます。
いいえ、それはOKではありません。いわゆる非正規化値(非正規)、0.0に等しい比較した場合、偽比較するであろう(非ゼロ)が、式で使用された場合(0.0になる)に正規化されるであろう。したがって、ゼロによる除算を回避する機構としてこれを使用することは安全ではありません。代わりに、1.0を追加し、1.0と比較します。これは、すべてのsubnormalsがゼロとして扱われることを保証します。
これを試してみてください、あなたは==、ダブル/フロートのための信頼性がないことがわかります。
double d = 0.1 + 0.2;
bool b = d == 0.3;
ここ<のhref = "https://www.quora.com/Why-is-0-1+0-2-not-equal-to-0-3-in-most-programming-languagesですQuoraのから#」のrel = "nofollowをnoreferrer">答えでます。
実は、私は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;