【发布时间】:2015-06-14 17:46:02
【问题描述】:
我有以下代码:
#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)时,它会打印“等于”的预期结果。
但是,当按照上述方式编译并在虚拟机(ubuntu 10.10,virtualbox 映像)上运行相同的代码时,它会输出“不等于” - 这是设置了 O3 和 O2 标志但未设置 O1 和以下。当使用 clang(O3 和 O2)编译并在虚拟机上运行时,我得到了正确的结果。
我了解 1.1 无法使用 double 正确表示,并且我已阅读 “每个计算机科学家应该了解的浮点运算知识” 所以请不要指点我,这似乎是 GCC 所做的某种优化,但它似乎在虚拟机中不起作用。
有什么想法吗?
注意:C++ 标准说在这种情况下的类型提升是依赖于实现的,难道 GCC 使用了更精确的内部表示,当应用不等式测试时它仍然成立 - 由于额外的精度?
UPDATE1: 对上述代码进行以下修改,现在可以得到正确的结果。似乎在某些时候,无论出于何种原因,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;
}
UPDATE2: 对于那些询问代码的 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;
}
UPDATE3 解决方案:将 virtualbox 升级到版本 4.1.8r75467 解决了该问题。然而,他们仍然存在一个问题,那就是:为什么 clang 构建工作。
【问题讨论】:
-
看看编译器的输出。它产生什么代码?
-
在这两种情况下你使用相同版本的 GCC 吗?
-
这个问题很难回答,因为它发生在一个非常具体的环境中。最好的方法是反汇编你的代码并检查它在做什么。
-
好问题。两台机器上的gcc版本是一样的吗?如果你在一台机器上编译然后将生成的应用程序复制到另一台机器上会怎样?那么输出有区别吗?
-
@Mr Lister:两台机器的 gcc 版本是一样的。我尝试在本机机器上构建的二进制文件中进行复制,但我得到了同样的错误结果。
标签: c++ optimization compiler-construction double-precision vm-implementation