我有以下代码:
#include <cstdio>
int main()
{
if ((1.0 + 0.1) != (1.0 + 0.1))
printf("not equal\n");
else
printf("equal\n");
return 0;
}
使用gcc(4.4、4.5和4.6)的O3编译并在本机(ubuntu 10.10)上运行时,它会输出预期的“equal”结果。
然而,当以上述方式编译相同的代码并在虚拟机(ubuntu 10.10,virtualbox镜像)上运行时,它输出“not equal”--这是当设置了O3和O2标志但未设置O1及以下标志时的情况。当使用clang(O3和O2)编译并在虚拟机上运行时,我得到了正确的结果。
我知道1.1不能用double正确地表示,并阅读了“计算机科学家应该了解的关于浮点运算的一切”,所以请不要把我指向那里,这似乎是GCC进行的某种优化,在虚拟机中不能正常工作。
有什么想法吗?
注意:C++标准规定,此类情况下的类型提升是取决于具体实现的,可能是GCC使用了更精确的内部表示,因此在应用不等式测试时保持为真--由于额外的精度?
更新1:以上代码的以下修改现在导致正确的结果。似乎在某个时候,由于某种原因,GCC关闭了浮点控制字。
#include <cstdio>
void set_dpfpu() { unsigned int mode = 0x27F; asm ("fldcw %0" : : "m" (*&mode));
int main()
{
set_dpfpu();
if ((1.0 + 0.1) != (1.0 + 0.1))
printf("not equal\n");
else
printf("equal\n");
return 0;
}
更新2: 对于那些询问代码是否为const表达式的人,我已经将其更改如下,但在使用GCC编译时仍然失败。- 但我认为优化器可能会将以下内容转换为const表达式。
#include <cstdio>
void set_dpfpu() { unsigned int mode = 0x27F; asm ("fldcw %0" : : "m" (*&mode));
int main()
{
//set_dpfpu(); uncomment to make it work.
double d1 = 1.0;
double d2 = 1.0;
if ((d1 + 0.1) != (d2 + 0.1))
printf("not equal\n");
else
printf("equal\n");
return 0;
}
更新3解决方案:将VirtualBox升级到版本4.1.8r75467可解决该问题。但是仍然存在一个问题,那就是:为什么clang版本能够工作。