我有一些简单的代码正在比较两个float值,以说明我在GCC优化中看到的一个问题,并希望有人可以帮助我弄清楚为什么它产生的输出在某些可重复的情况下会有所不同。
首先,我知道将浮点值与 == 进行比较是不好的,因为您可能会在尾数中偏离一些非常小的数量,但是在我的示例中情况并非如此。我遇到的问题是基于 2 个因素的输出变化。 1) 我传入的优化标志,以及 2) 如果我取消注释 std::cout 行。
为什么 GCC 生成的代码在 -O2 下运行方式不同?
如果取消注释打印,为什么在 -O2 下编译的代码可以工作?
这是我正在测试的代码:
#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 ) 编译时,我得到以下输出:
该输出是正确的,您可以看到浮点数(new_val 和 old_val)的位是相同的。当我使用 -O2 标志( g++ -O2 test.cpp )编译时,我得到以下信息:
我会认为这个输出是错误的。即使这两个值是 相同的 位明智的,减去它们和 == 检查表明它们是不同的。如果我然后取消注释 std::cout 行,并使用 -O2 标志( g++ -O2 test.cpp )重建,我会得到以下信息:
这是正确的 old_val == new_val,即使减法仍然显示出轻微的差异。
如果英尺为 2000 而不是 20000,则此代码在 -O2 下也有效。
谁能解释为什么编译后的代码会这样?我想知道为什么 2 位相同的浮点值不能与 == 进行比较。
gcc版本3.4.4
最佳答案
优化级别和周围代码可能会影响 diff_val
计算中使用的值是从内存中获取还是从寄存器中获取。处理器
在一种情况下可能使用 80 位内部浮点寄存器,而 32 位浮点寄存器
在另一种情况下,会从内存中获取点值,从而产生意外结果。
避免使用 ==
进行浮点比较的另一个原因!
关于linux - GCC 在不同优化级别处理 Float 比较不同,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/3765200/