web-dev-qa-db-ja.com

「-Weverything」は「浮動小数点を==または!=と比較するのは安全ではありません」を生成します

次のようにdoubleに変換する文字列があります。

double d = [string doubleValue];

doubleValueのドキュメントによると、オーバーフローすると、このメソッドはHUGE_VALまたは-HUGE_VALのいずれかを返します。これは私が以前にこれをチェックした方法です:

if (d == HUGE_VAL || d == -HUGE_VAL)
   //overflow

ここで、新しい「-Weverything」警告フラグを追加してから、コンパイラは次のように文句を言います。

Comparing floating point with == or != is unsafe

この問題を解決するにはどうすればよいですか?どのようにすべき私はこれらの比較をしていますか?


2つの「通常の」浮動小数点数(つまり、「HUGE_VAL」ではない)の比較についても同じ質問があります。例えば、

double a, b;
//...
if (a != b) //this will now yield the same warning
  //...

これはどのように解決する必要がありますか?

24
NoobOverflow

この警告について心配する必要はありません。あなたを含め、多くの場合それはナンセンスです。

doubleValueのドキュメントには、オーバーフロー時にHUGE_VALまたは-HUGE_VALに十分近いものが返されるとは記載されていません。オーバーフローが発生した場合、これらの値を正確に返すと書かれています。

つまり、オーバーフローが発生した場合にメソッドによって返される値は、==HUGE_VALまたは-HUGE_VALと比較します。

そもそも警告が存在するのはなぜですか?

0.3 + 0.4 == 0.7を考えてみましょう。この例はfalseと評価されます。あなたが出会った警告の作者を含む人々は、浮動小数点==は不正確であり、予期しない結果はこの不正確さから来ると考えています。

それらはすべて間違っています。

浮動小数点additionは、ある意味不正確であるため、「不正確」です。これは、要求した操作に最も近い表現可能な浮動小数点数を返します。上記の例では、変換(10進数から浮動小数点へ)と浮動小数点の加算が奇妙な動作の原因です。

一方、浮動小数点equalityは、他の離散型の場合とほぼ同じように機能します。浮動小数点の等式は正確です。マイナーな例外(NaN値と+0。および-0。の場合)を除いて、検討中の2つの浮動小数点数が同じ表現である場合に限り、等式はtrueと評価されます。

2つの浮動小数点値が等しいかどうかをテストするためにイプシロンは必要ありません。そして、 Dewarが実質的に言っている のように、警告が意味をなすためには、例0.3 + 0.4 == 0.7の警告は+ではなく==にあるべきです。

最後に、イプシロン内と比較すると、等しくない値は等しく見えることを意味します。これは、すべてのアルゴリズムに適しているわけではありません。

37
Pascal Cuoq

この場合、>=<=を使用してみてください。

10
echristopherson

比較について確信があり、それをclangに伝えたい場合は、コードを次のように囲みます。

#pragma clang diagnostic Push
#pragma clang diagnostic ignored "-Wfloat-equal"
/* My code triggering the warnings */
#pragma clang diagnostic pop
7
yageek

この非常に単純なユースケースではおそらく必要ありませんが、数値が-1に等しいかどうかを確認しようとした場合に、潜在的な不一致をどのように説明するかの例を次に示します。

#include <float.h>
#include <math.h>

int main(void) {
  float sales = -1;

  // basically if sales == -1
  if (fabs(1 + sales) < FLT_EPSILON) {
    return 0;
  }
}
0
ericcurtin

Float型が不正確であるため、floatを==または!=と比較しないでください。これらの演算子を使用すると、予期しないエラーが発生する可能性があります。代わりに、フロートが互いに距離内にあるかどうかをテストする必要があります(ほとんどの場合「イプシロン」と呼ばれます)。

次のようになります。

const float EPSILON = 1.0f; // use a really small number instead of this

bool closeEnough( float f1, float f2)
{
    return fabs(f1-f2)<EPSILON; 
    // test if the floats are so close together that they can be considered equal
}
0
Brainbot