2010-09-21 69 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