3

我发现了一个有趣的案例,相同的 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!

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

但是,使用:

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

将返回是!在两台机器上。

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

4

5 回答 5

14

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

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

于 2012-05-09T15:40:49.830 回答
12

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

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

于 2012-05-09T15:47:25.260 回答
2

这是因为浮点运算,请尝试使用 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!");
于 2012-05-09T15:43:52.400 回答
0

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

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

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

于 2012-05-09T15:44:10.737 回答
0

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

您可以在此处此处此处此处此处查看此内容,并且基本上可以在 google 搜索中看到任何结果floating point equality

于 2012-05-09T15:47:07.117 回答