"-Weverything"产生"比较浮动点与==或!=是不安全的"

Noo*_*low 23 cocoa objective-c llvm clang

我有一个字符串,我转换为像这样的双:

double d = [string doubleValue];
Run Code Online (Sandbox Code Playgroud)

文档doubleValue告诉我们,在溢出时,此方法返回HUGE_VAL-HUGE_VAL.这就是我之前检查过的方法:

if (d == HUGE_VAL || d == -HUGE_VAL)
   //overflow
Run Code Online (Sandbox Code Playgroud)

现在,由于添加了新的"-Weverything"警告标志,编译器现在会抱怨

Comparing floating point with == or != is unsafe
Run Code Online (Sandbox Code Playgroud)

我该如何解决这个问题?如何应该我做这些比较?


关于比较两个"正常"浮点数(即不是"HUGE_VAL"),我也有同样的问题.例如,

double a, b;
//...
if (a != b) //this will now yield the same warning
  //...
Run Code Online (Sandbox Code Playgroud)

该如何解决?

Pas*_*uoq 37

您无需担心此警告.这在许多情况下都是无稽之谈,包括你的.

文档doubleValue并没有说它返回足够接近HUGE_VAL-HUGE_VAL溢出的东西.它表示在溢出的情况下它会返回这些值.

换句话说,溢出时方法返回的值==HUGE_VAL或相比较-HUGE_VAL.

为什么警告首先存在?

考虑这个例子0.3 + 0.4 == 0.7.此示例的计算结果为false.人们,包括你遇到的警告的作者,认为浮点==是不准确的,并且意外的结果来自这种不准确性.

他们都错了.

浮点加法是"不准确的",因为某些不准确的意义:它返回您请求的操作的最近的可表示浮点数.在上面的示例中,转换(从十进制到浮点)和浮点加法是奇怪行为的原因.

另一方面,浮点相等与其他离散类型的工作方式非常相似.浮点相等是精确的:除了小的异常(NaN值和+0.和-0.的情况)之外,当且仅当所考虑的两个浮点数具有相同的表示时,等式才计算为true.

您不需要epsilon来测试两个浮点值是否相等.而且,正如杜瓦在实质上所说的那样,示例中的警告0.3 + 0.4 == 0.7应该依据+而不是==警告才有意义.

最后,与epsilon相比,意味着不相等的值看起来相等,这不适合所有算法.

  • @NoobOverflow如果您真的希望使编译器满意,请测试`d> = HUGE_VAL || d <= -HUGE_VAL`。它在不使用“ ==”的情况下计算相同的事物。但是我建议不要使用警告。 (2认同)
  • 它需要260个单词来解释何时以及如何使浮点数相等操作本身不准确,这一事实证明了编译器工程师的决定。这是一个警告,因为尽管操作没有错,但它仍然是漏洞的热点。对于初级工程师来说尤其如此……由于行为完全相同,我已经看到了很多生产问题。警告不是胡说八道,它是防御性的和明智的。 (2认同)
  • @AdamKaplan它只需要260个单词,因为2600万个迷信,有害的单词都是按照"浮点值并不代表精确理性"的方式写成的.如果你要坚持答案的长度,那么Jon Skeet的大部分建议都是通过相同的推理得到的. (2认同)

ech*_*son 10

在这种情况下,尝试使用>=<=.

  • 为什么那更好? (3认同)
  • 好吧,它没有比较严格的相等,所以它安抚了编译器.并且由于没有任何东西可以大于HUGE_VAL或小于-HUGE_VAL,因此它的工作原理相同. (3认同)

yag*_*eek 7

如果你确定你的比较,并且你想告诉它铿锵声,请用以下代码包围你的代码:

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wfloat-equal"
/* My code triggering the warnings */
#pragma clang diagnostic pop
Run Code Online (Sandbox Code Playgroud)