【问题标题】:Same C++ 'if' statement, different results on Linux/Windows相同的 C++ 'if' 语句,在 Linux/Windows 上的结果不同
【发布时间】:2012-05-09 15:39:26
【问题描述】:

我发现了一个有趣的案例,相同的 C++ 代码在不同的系统上产生不同的结果。

#include <cstdio>
int main()
{
    int a=20, b=14;
    if(a*1.0/b*(a+1)/(b+1)==2) printf("YES!");
    else printf("NO!");
}

使用 GCC 4.6.3 在 Ubuntu Linux 12.04 上编译,它输出 YES!

在 Windows 7 上使用 GCC 4.6.2 编译,输出 NO!

但是,使用:

double  c = a*1.0/b*(a+1)/(b+1);
if (c==2) printf("YES!");
...

将在两台机器上返回 YES!

任何想法为什么会出现这种差异?这是由编译器版本不匹配引起的(路径级别版本号应该不那么重要)?以及为什么它在Windows机器上实际输出NO!,而这种情况显然是正确的?

【问题讨论】:

标签: c++ gcc mingw multiplatform


【解决方案1】:

因为您正在对浮点类型进行相等比较,通常不应该依赖于机器到机器(或从编译器到编译器等)的特定位精确行为。

可能的原因包括编译器选择何时将浮点结果移出宽(80 位)浮点寄存器(语言标准和 IEEE-754 浮点标准都没有施加任何特殊要求,AFAIK) .

【讨论】:

  • 我认为知道编译器或处理器的哪个属性是造成差异的原因会很有趣。如果不精确,IEEE 浮点应该是一致的。
  • @MarkRansom:由于数字不准确,因此无法保证一致性。重新安排操作的顺序(在数学上应该是一致的)可以产生不同的结果,这仅仅是因为所涉及的值的准确性。编译器只保证数学一致性而不是准确性一致性。
  • @LokiAstari,gcc 有一个编译器开关,可以在结果不能保证匹配时启用数学运算的重新排列。
【解决方案2】:

这只是一个猜测,您需要查看编译器的程序集输出才能确定。

可能一个编译器将中间结果留在浮点寄存器中,而另一个编译器将结果写入内存,将其从 80 位四舍五入到 64。也可能一个编译器使用 SSE 而另一个不使用。

【讨论】:

  • +1(几乎)每个人都知道 FP 问题,但您试图猜测造成这种差异的原因
  • 是的,没错,感谢您提出这个问题的原因:-)
  • 澄清一下,20/14 可以使用 80 位精度精确表示,但不能使用 32 位精度(未尝试 64)。 Windows 版本将中间值存储在 RAM 中或使用 SSE,而 Ubuntu 版本将中间值保存在 FPU 中。
  • @Skizz,80 位怎么可能有帮助? 14 不是 2 的幂这一事实意味着分数将无限重复。
  • @Skizz,无论您使用多少位,它都永远不会准确。我猜你的意思是向下舍入与向上舍入。
【解决方案3】:

这是因为浮点运算,请尝试使用 epsilon 比较:

#define EPSILON_EQUAL(a,b) ( fabs((a)-(b)) < (0.0001f) )

float f = a*1.0/b*(a+1)/(b+1);
if(EPSILON_EQUAL(f,2.0f)) printf("YES!");

【讨论】:

  • 感谢您提出 epsilon 比较的建议,即使您的回答没有解释为什么会发生此问题 ;)
  • 我想这与在第一个示例中使用 float (在 if 语句中),在第二个示例中使用 double 的事实有关。这是看起来与您的问题相似的 SO:stackoverflow.com/questions/7702177/…
【解决方案4】:

测试浮点数之间的相等性是有问题的。这是因为四舍五入的错误,互联网上有很多很多的文字。

你可以看到这个hereherehereherehere,基本上任何结果都可以在谷歌搜索floating point equality看到。

【讨论】:

  • 这是真的,但没有解释为什么它因平台而异。
  • @OliCharlesworth,就像我说的,有很多关于这方面的文字。在我看来,再解释一次是没有意义的。
【解决方案5】:

因为精度问题,这样比较浮点数是不正确的。

在数学中 2/3= (0.6666666 ... to infinity)//小学数学 :) 没有问题。

在计算中,此计算是在浮点单元上进行的(类似于 CPU,但专用于浮点计算)。现在这个浮点单元(FPU)可能会给你一个非常接近你实际答案的数字,但它们并不完全相同。因为它会截断结果。有一个专门用于浮点运算的整个领域。简而言之,切勿在比较中使用浮点数,因为您可能会得到相互矛盾的结果。

【讨论】:

  • 这是真的,但没有解释为什么它因平台而异。
猜你喜欢
  • 2013-05-20
  • 2016-12-05
  • 2018-07-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多