2010-09-21 66 views
6

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

当与-O0,-O1,和-O3(克++ -O TEST.CPP)在Linux/cygwin的编译时,得到以下输出:


$ ./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)的比特是相同的。当我与-02标志(G ++ -02 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


我会考虑这个输出错误。即使这两个值是相同位智者,扣除他们和==检查表明他们是不同的。


$ ./a.exe
随机COUT:如果我再取消对性病::法院线,并与-02标志(G ++ -02 TEST.CPP)我得到以下重建这使得这项工作
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正确的,即使减法仍然略有差异。

此代码也可以-02下,如果脚是2000年,而不是20000

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

gcc版本3.4.4

回答

10

优化水平和周围的代码可能会影响是否在diff_val计算中使用的值被从存储器中取出,或从寄存器。处理器 可能在一种情况下使用80位内部浮点寄存器,在另一种情况下可能使用来自内存的32位浮点值,从而产生意外结果。

另一个避免使用==进行浮点比较的原因!

+2

+1。这是(几乎肯定)的问题。无论优化级别如何,使用“-ffloat-store”选项进行编译都会得到一致的结果。 – eldarerathis 2010-09-21 23:41:31

+0

好吧,也许我是一个noob,但你应该怎么做浮点比较? <= and > =?只需链接到相关信息就足够了。谢谢。 – 2010-09-22 00:16:55

+0

@Robert:'fabs(a-b) 2010-09-22 00:42:03