System.Doubleを「0」(数値、整数?)と比較する正しい方法


87

申し訳ありませんが、これは簡単な愚かな質問かもしれませんが、確かに知る必要があります。

私はこのif表現を持っています、

void Foo()
{
    System.Double something = GetSomething();
    if (something == 0) //Comparison of floating point numbers with equality 
                     // operator. Possible loss of precision while rounding value
        {}
}

その表現はと等しいですか

void Foo()
{
    System.Double something = GetSomething();
    if (something < 1)
        {}
}

?問題が発生する可能性があるため、ifたとえば値0.9でと入力します。


3
// Comparison of floating point numbers with equality // operator. 本当にそれを指定する必要がありましたか?:)
ジョージジョンストン

1
嫌です。0から1の間にたくさんの値があります。それをテストして自分の目で確かめてみませんか?
Igby Largeman 2011

12
私はResharperが書いたのと同じように、私の焦点がどこにあるかを示すために書いた。
radbyx 2011

@Charles:また、以下は0よりも数字が多い
ブライアン

回答:


114

さて、値を0に近づける必要がありますか?「無限の精度」で0になる可能性のある多くの浮動小数点演算を実行すると、結果が「非常に近い」0になる可能性があります。

通常、この状況では、ある種のイプシロンを提供し、結果がそのイプシロン内にあることを確認します。

if (Math.Abs(something) < 0.001)

使用する必要のあるイプシロンはアプリケーション固有です。これは、実行している内容によって異なります。

もちろん、結果が正確にゼロである必要がある場合は、単純な同等性チェックで問題ありません。


実際、私はそれを正確にゼロにする必要があります、それはどのように見えるでしょうか?Double.Zeroを探しましたが、運が良かったです。一定の権利がありますか?ところで、ありがとう、私は今イプシロンの部分を手に入れました:)
radbyx 2011

24
@radbyx:を使用してください== 0。あなたはそこにリテラルを持っています-それはかなり一定です:)
Jon Skeet 2011

35

somethingそれ以外の操作の結果から割り当てられている場合は、something = 0次を使用することをお勧めします。

if(Math.Abs(something) < Double.Epsilon)
{
//do something
}

編集:このコードは間違っています。イプシロンは最小の数ですが、完全にゼロではありません。ある数値を別の数値と比較したい場合は、許容範囲を考える必要があります。.00001を超えるものは気にしないとしましょう。それがあなたが使う番号です。値はドメインによって異なります。ただし、ほとんどの場合、Double.Epsilonになることはありません。


2
これは、例えば、丸め問題を解決しないMath.Abs(0.1f - 0.1d) < double.Epsilonfalse
トーマスLulé

6
Double.Epsilonは、このような比較には小さすぎます。Double.Epsilonは、doubleが表すことができる最小の正の数です。
エフゲニーナボコフ

3
これは、0と比較するのと実質的に同じであるため、意味がありません。
1– Gaspa79 2017

1
目標は、==を使用せずに0の概念と比較することです。少なくともそれは数学的に感覚を作ります。手元にダブルがあり、==なしのゼロの概念と比較したいとします。丸めなどの理由でdoubleが0dと異なる場合、テストフィルはfalseを返します。この比較はどのdoubleに対しても有効であるように見え、このdoubleが表現できる最小数よりも小さい場合にのみtrueを返します。これは、0の概念をテストするための適切な定義のようです。
sonatique 2017年

3
@MaurGi:あなたは間違っています: double d = Math.Sqrt(10100)*2; double a = Math.Sqrt(40400); if(Math.Abs(a - d) < double.Epsilon) { Console.WriteLine("true"); }
sonatique 2017年

26

君の somethingは、doubleであり、あなたはそれを行で正しく識別しました

if (something == 0)

我々は持っているdouble(LHS)左側とint右側(RHS)。

しかし今、あなたはlhsがに変換されると思うようですint、そしてそれから==符号は2つの整数を比較します。それ何が起こるかではありませんから double の変換int明示的であり、「自動的に」行うことはできません。

代わりに、逆のことが起こります。rhsはに変換されdouble==符号は2つのdouble間の等式テストになります。この変換は暗黙的(自動)です。

書く方が(一部の人は)良いと考えています

if (something == 0.0)

または

if (something == 0d)

2つのダブルを比較しているのはすぐだからです。ただし、コンパイラはどのような場合でも同じことを行うため、これはスタイルと読みやすさの問題です。

場合によっては、Jon Skeetの回答のように「許容範囲」を導入することも適切ですが、その許容範囲doubleも同様です。それは可能性のコースも1.0、あなたが望むならば、それは[少なくとも厳密に正]の整数である必要はありません。


17

単に警告を抑制したい場合は、次のようにします。

if (something.Equals(0.0))

もちろん、これはドリフトが問題ではないことがわかっている場合にのみ有効な解決策です。私はよくこれを行って、ゼロで除算しようとしているかどうかを確認します。


4

正直なところ、同じだとは思いません。あなた自身の例を考えてみましょう:何か= 0.9、または0.0004。最初のケースではFALSEになり、2番目のケースではTRUEになります。このタイプを処理するために、私は通常、精度のパーセンテージを定義し、その精度内で比較します。あなたのニーズに依存します。何かのようなもの...

if(((int)(something*100)) == 0) {


//do something
}

お役に立てれば。


2
何かが正確にゼロでなければなりません。
radbyx 2011

だからあなたは幸運な人です、この場合:)
Tigran 2011

3

これが問題を提示する例です(LinQPadで準備されています-メソッドのConsole.Writeline代わりに使用するだけではない場合Dump):

void Main()
{
    double x = 0.000001 / 0.1;
    double y = 0.001 * 0.01; 

    double res = (x-y);
    res.Dump();
    (res == 0).Dump();
}

xとyはどちらも理論的には同じで、0.00001に等しくなりますが、「無限の精度」がないため、これらの値はわずかに異なります。残念ながらfalse、通常の方法で0と比較すると、わずかに戻ることができます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.