Jar*_*sie 21 c++ compiler-construction optimization double-precision vm-implementation
我有以下代码:
#include <cstdio>
int main()
{
if ((1.0 + 0.1) != (1.0 + 0.1))
printf("not equal\n");
else
printf("equal\n");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
当使用gcc(4.4,4.5和4.6)使用O3编译并本机运行(ubuntu 10.10)时,它会打印预期的"相等"结果.
但是,当如上所述编译并在虚拟机(ubuntu 10.10,virtualbox image)上运行时,它输出"不相等"的情况下相同的代码 - 这是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;
}
Run Code Online (Sandbox Code Playgroud)
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;
}
Run Code Online (Sandbox Code Playgroud)
UPDATE3解决方案:将virtualbox升级到版本4.1.8r75467解决了该问题.然而,他们仍然是一个问题,那就是:为什么clang构建起作用.
aho*_*fer 10
更新:请参阅此文章如何处理浮点计算中的过度精度? 它解决了扩展浮点精度的问题.我忘记了x86中的扩展精度.我记得一个应该是确定性的模拟,但是在Intel CPU上比在PowePC CPU上给出了不同的结果.原因是英特尔扩展的精密架构.
该网页讨论了如何将Intel CPU投入双精度舍入模式:http://www.network-theory.co.uk/docs/gccintro/gccintro_70.html.
虚拟机是模拟器,可以模拟特定的指令集或体系结构,并且大多数成功.然而,它们只是模拟器,并且受制于它们自己的实现怪癖或设计问题.
如果您还没有,请发布问题forums.virtualbox.org并查看社区对此的评价.
是的,这是非常奇怪的行为,但实际上可以很容易地解释:
在x86浮点寄存器内部使用更高的精度(例如80而不是64).这意味着计算1.0 + 0.1将在寄存器中以更高的精度计算(并且因为在所有那些将要使用的额外位,所以1.1不能精确地以二进制表示).仅当将结果存储到存储器时才会被截断.
这意味着什么很简单:如果你将从内存加载的值与在寄存器中新计算的值进行比较,你会得到一个"不相等"的回,因为一个值被截断而另一个没有.因此,这与VM /无VM无关,它只取决于编译器生成的代码,这些代码很容易随着我们看到的那样波动.
将它添加到不断增加的浮点惊喜列表中..