GCC处理在不同的优化级别上浮点数比较不同

我有一些比较两个浮点值的简单代码来说明我在GCC的优化中看到的一个问题,并希望有人能帮助我弄清楚为什么在一些可重复的情况下它产生的输出是不同的。

首先,我知道将浮点值与==比较是不好的,因为尾数可能会有一些非常小的数字,但是在我的例子中并不是这样。 我的问题是基于2个因素的输出变化。 1)我传入的优化标志,2)如果我取消注释std :: cout行。

为什么GCC代码在-O2下运行不同? 为什么在-O2下编译的代码工作,如果我取消注释打印?

这是我正在testing的代码:

#include <iostream> const float ft_to_m = (float)0.3048; const float m_to_ft = (float)3.28083989501; float FeetToKilometers( float & Feet ) { float Kilometers; Kilometers = (ft_to_m * Feet) / 1000.; return Kilometers; } int main(void) { float feet = 20000.; float old_val = 0; float new_val = FeetToKilometers(feet ); float diff_val = 0; int *old_int = reinterpret_cast<int*>(&old_val); int *new_int = reinterpret_cast<int*>(&new_val); for (int i=0; i<2; i++) { new_val = FeetToKilometers(feet ); diff_val = old_val-new_val; //std::cout << "Random COUT that makes this work" << std::endl; if(old_val==new_val) { std::cout << "old_val==new_val" << std::endl; std::cout << std::hex << *old_int << "," << std::hex << *new_int << std::endl; std::cout << "diff_val = " << diff_val <<std::endl; } else { std::cout << "old_val!=new_val" <<std::endl; std::cout << std::hex << *old_int << "," << std::hex << *new_int << std::endl; std::cout << "diff_val = " << diff_val <<std::endl; old_val=FeetToKilometers(feet); } } return 0; } 

在linux / cygwin上用-O0,-O1和-O3(g ++ -O test.cpp)编译时,我得到如下输出:


$ ./a.exe
old_val!= new_val
0,40c3126f
diff_val = -6.096
old_val == new_val
40c3126f,40c3126f
diff_val = 0


该输出是正确的,你可以看到浮点数(new_val和old_val)是相同的。 当我用-O2标志(g ++ -O2 test.cpp)进行编译时,我得到以下结果:


$ ./a.exe
old_val!= new_val
0,40c3126f
diff_val = -6.096
old_val!= new_val
40c3126f,40c3126f
diff_val = 1.19209e-07


我会认为这个输出是错误的。 即使这两个值是相同的比特明智的,减去他们和==检查表明他们是不同的。 如果我然后取消注释std :: cout行,并使用-O2标志(g ++ -O2 test.cpp)重build,我得到以下内容:


$ ./a.exe
随机COUT,使这项工作
old_val!= new_val
0,40c3126f
diff_val = -6.096
随机COUT,使这项工作
old_val == new_val
40c3126f,40c3126f
diff_val = 1.19209e-07


这在old_val == new_val中是正确的,尽pipe减法仍然显示出细微的差别。

如果脚是2000而不是20000,这个代码也可以在-O2下工作。

任何人都可以解释为什么编译的代码是这样的行为? 我想知道为什么2位相同的浮点值不能与==比较。

海合会版本3.4.4

优化级别和周围代码可能会影响在diff_val计算中使用的值是从内存还是从寄存器中获取。 处理器在一种情况下可能使用80位内部浮点寄存器,在另一种情况下可能使用内存中的32位浮点值,从而产生意外的结果。

还有一个原因,以避免使用==浮点比较!