2つのフロートの等価性のテスト:現実的な例


8

2つの浮動小数点数の等価性をテストすることは、プログラミングで通常どのような意味がありますか?

すなわち

a == b 

ここで、aとbはどちらも浮動小数点数です。

私の素朴な印象は、ある程度の耐性イプシロンに対して常に違いをテストするということです。

私が間違っている?フロートの等価性をテストすることは、特定のコンテキストで意味がありますか?

野生の例はありますか?つまり、実際のコードベースまたはアプリケーションから、gitなどにあります。

PS。floatで等値演算子を使用することは、一部のコンテキストでは実際に意味があると想定しています。そうでなければ、ほとんどのプログラミング言語がそれを許可する理由。


1
これは数値アルゴリズムの実際的な問題に関するものであるため、私は計算科学に移行しています。

この特定の質問をすることで解決しようとしている問題を知るのに役立つかもしれません。meta.stackexchange.com/q/66377
キリル

1
@Krill問題は好奇心です。いつ使用しないかについてのアドバイスを知っています。しかし、演算子がまだ許可されている場合は、それを使用することが本当に正しい場合があるはずです。しかし、それらのueケースは明白ではありませんでした。だから私は知りたかった。そして、答えはいくつかの良い例をもたらします。
curious_cat 2016年

回答:


5

私の素朴な印象は、ある程度の耐性イプシロンに対して常に違いをテストするということです。

このアイデアの素朴な実装は、おそらく、IEEE 754標準が想定している重要な特殊なケース(無限、非正規化数...)を処理するために、等価比較演算子を利用する必要があります。

浮動小数点比較どのように行うべきですか?を見てください。

...

if (a == b)  // shortcut, handles infinities
  return true;

if (a == 0 || b == 0 || diff < Float.MIN_NORMAL) {
  // a or b is zero or both are extremely close to it
  // relative error is less meaningful here

...


時々、正解が1つだけあり、正確な平等が必要な場合があります。実装の正しさをテストすることは良い例です(つまり、40億フロートしかないので、すべてテストしてください!)。


OR句内のa == 0のテストは、diff <Float.MIN_NORMALによって冗長になりませんか?
curious_cat 2016年

3

明らかな例==okですが、ときであるab同じ数、すなわちであるa=c; b=cかどうかを確認するには例えば、ab同じように初期化されました。もちろん、|a-b| < epsilonここでも機能します。唯一の問題は、どれほど小さいepsilonかです。

また、a == bコンパイルして1つの命令に|a-b| < epsilonすると、かなりの数になります。


ありがとう!典型的なコーディング状況で、aとbが同じように初期化されているかどうかを知りたいのはいつですか?これを使用してコードスニペットを投稿できますか?つまり、ソースを調べて伝えることができないのですか?
curious_cat 2016年

1
@curious_catでは、タイルのグリッドを使用してMinecraftのようなゲームを作成しているとします。これらのタイルが何らかの理由でフロート座標を持ち、のような明らかなループで初期化されたとしますfor x in [0..n] step w: for y in [0..n] step w: add_tile(x, y)。その場合t1.x == t2.x、2つのタイルが1つの平面にあるかどうかをテストする完全に安全な方法です。あなただけの必要がある|a-b|<epsilonときab同じ値を取得することになっていた別の計算の結果です。しかし、多くの場合、1つの計算の結果が2つの変数に格納されるか、変数を定数で上書きします。
KarolisJuodelė16年

とても良い例です!ありがとう。理にかなっています。私が本当に得た最初の実際のサウンドのユースケース!あなたはそれをあなたの答えに加えるべきです!
curious_cat 2016年

2

極端な例:IBMは、積和演算命令を融合したプロセッサを構築した最初の企業でした。その命令を使用して、IEEE-754標準に従って平方根を計算する非常に高速な方法を作成しました。このメソッドは、単一の入力値1≤x <4の場合に失敗します。xが4未満の浮動小数点数として表現可能な最大数の場合、結果は正しく丸められません。

したがって、実装のどこかで、xがその特定の値と等しいかどうかを確認します。彼らは他の人ではなくその価値を認めたいと思っています。


ありがとう!それはどんな価値ですか、どんな考えですか?これを読むための参考文献は見つかりませんでした。リンクを投稿できますか?
curious_cat 2016年

2

私の素朴な印象は、ある程度の耐性イプシロンに対して常に違いをテストするということです。私が間違っている?フロートの等価性をテストすることは、特定のコンテキストで意味がありますか?

ユニークなレシピはありません。で、この記事あなたは、技術とコードとの完全な答えを見つけることができる包括的治療は、そこにあります。

要約すると、主に3つのケースがあります。

  • ゼロと比較
  • ゼロ以外と比較
  • 2つの任意の数値を比較する

許容値との比較を使用するというあなたのアイデアは、いくつかのケースに適していますが、記事の中で説明されている最後の場所にあるUnit(ULP)に基づくテクニックもあります。

浮動小数点数で等値演算子を使用することは、一部のコンテキストでは実際に意味があると想定しています。そうでなければ、ほとんどのプログラミング言語がそれを許可する理由。

上記のように、それを使用できる状況がありますが、警告されます。たとえば、gccコンパイラには警告があります。

warning: comparing floating point with == or != is unsafe

更新

この議論の上にいくつかの考慮事項を追加しa == bます。それらはケースに厳密に関連していません。

表現との平等

ケースを考える:

a + b == c 

a b c

ab==cflfla+flb==flc
  • flバツバツ

|aa+b|erra+|ba+b|errb
errバツ=|バツflバツ||バツ|

したがって、この場合、の使用==はよりデリケートです。

異なる環境での移植

異なる環境(異なるマシン)にコードを移植すると、いくつかの異なる結果を得ることができます(たとえば、単体テストを考えてみてください)。==デリケートな場合もございます。


ああ!したがって、警告が生成されます。ありがとう。だから今の私の印象は、99%のコーディングケースでは、フロートの等値比較はエラーですが、それが意味のある非常に少数のコーナーケースでも許可されているということです。
curious_cat 2016年

1
@curious_catはい、あなたに同意します。メモを追加します。
Mauro Vanzetto、2016年

0

あなたの「素朴な印象」は「素朴な印象」ではありません-それは浮動小数点演算について読んで半分しか理解していない結果です。「素朴な印象」とは、aとbが等しいかどうかを調べるために、それらが等しいかどうかを尋ねる明らかな印象です。

2つの浮動小数点数が等しいかどうかを知る必要がある状況はたくさんあります。丸め誤差がないか、丸め誤差による変動がないことがわかっている状況はたくさんあります。10進数を浮動小数点に変換するのと同じです。

これは良い例です:誰かが任意の2つの浮動小数点数a、bに対して(b + a + b)と(b + b + a)の結果は同じであると主張し、その主張をテストしたいとします。2つの浮動小数点数が等しいかどうかを比較せずにそれを試してください。

これがより良い方法です。浮動小数点数のセットを作成してみてください。


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