2014-01-09 17 views
4

我的程序中有一個非常奇怪的錯誤。我無法錯誤可重複的代碼分離,但在我的代碼某個地方有:兩個雙打可以同時平等嗎?

double distance, criticalDistance; 
    ... 

    if (distance > criticalDistance) 
    { 
     std::cout << "first branch" << std::endl; 
    } 
    if (distance == criticalDistance) 
    { 
     std::cout << "second branch" << std::endl; 
    } 

在調試版本,一切都很好。只有一個分支得到執行。

但是在發佈版本中,所有的地獄都會打散,有時候兩個分支都會被執行。

這是很奇怪的,因爲如果我添加了else條件

if (distance > criticalDistance) 
    { 
     std::cout << "first branch" << std::endl; 
    } 
    else if (distance == criticalDistance) 
    { 
     std::cout << "second branch" << std::endl; 
    } 

這不會發生。

請問,這可能是什麼原因?我正在使用gcc 4.8.1Ubuntu 13.10上一個32位電腦。

EDIT1:

我使用預編譯標誌

  • -std = GNU ++ 11
  • -gdwarf-3

EDIT2:

我不認爲這是由內存泄漏引起的。我用valgrind分析了版本和調試版本,內存分析器跟蹤單元化內存並檢測自修改代碼,我發現沒有錯誤。

EDIT3:

更改聲明

volatile double distance, criticalDistance; 

使問題消失。這是否確認woolstar's answer?這是一個編譯器錯誤?

EDIT4:

使用gcc的選項-ffloat店也解決了這個問題。如果我正確理解這是由gcc引起的。

+3

由於四捨五入錯誤,檢查雙打相等通常是不明智的。相反,檢查絕對值是否在一定的容差範圍內。 –

+0

@RobertJacobs謝謝!我意識到這一點。在這種情況下,我想比較嚴格的平等,因爲我比較的數字是從完全相同的計算創建的。 –

+0

你不會說你的發佈版本使用了什麼選項,但它是否包含'-fast-math'? –

回答

14
if (distance > criticalDistance) 
    // true 
if (distance == criticalDistance) 
    // also true 

我在我自己的代碼中看到過這種行爲。這是由於存儲器中存儲的標準64位值與英特爾處理器用於浮點計算的80位內部值之間的不匹配造成的。

基本上,當截斷爲64位時,您的值相等,但在80位值處測試時,其中一個稍大於另一個。在DEBUG模式下,這些值始終存儲在內存中,然後重新加載,以便它們總是被截斷。在優化模式下,編譯器重新使用浮點寄存器中的值,並且不會被截斷。

+6

另請參閱http://stackoverflow.com/a/20870215/420683 – dyp

+0

這其實可以。我使用的是英特爾處理器。 –

+1

有趣。這需要編譯器在一個比較中截斷值,但是不在另一個比較中,這看起來很奇怪。但是,是的,如果代碼比這裏顯示的更復雜,那很可能是原因。 +1 – jalf

2

請問,這可能是什麼原因?

未定義的行爲,又名。錯誤代碼。

沒有表現出這種行爲的IEEE浮點值。所以發生了什麼事是你正在做錯誤,這違反了你的編譯器做出的假設。

優化代碼時,編譯器假定您的代碼可以用C++標準描述。如果你做了任何C++標準未定義的東西,那麼這些假設就會被違反,從而導致「怪異」的執行。它可能與未初始化的變量或緩衝區溢出一樣「簡單」,導致堆棧或堆的某些部分被垃圾數據覆蓋,或者它可能更加微妙,您依賴於兩個操作之間的特定順序,即沒有標準保證。

這也許就是爲什麼你不能複製在一個小的測試案例(較小的測試代碼不包含錯誤代碼)的問題,或者,爲什麼你只看到錯誤的優化構建。

當然,您也可能偶然發現了一個編譯器錯誤,但代碼中的錯誤可能性更大。 :)

最重要的是,這意味着我們沒有真正有機會從您顯示的代碼段中調試問題。我們可以說「代碼不應該表現得像那樣」,但這就是全部。

+4

代碼中的錯誤可能不是問題。 – woolstar

+1

IEEE的真實性,但我們如何知道編譯器是否符合IEEE標準? –

+1

「沒有表現出這種行爲的IEEE浮點值。」如果它如此簡單,生活將會多麼美好。請參閱http://arxiv.org/abs/cs/0701192,或許查看關於「過度精確」的部分。 Monniaux的報告是關於C語言的,但實際上,C++標準留下了相同的大門,可以被編譯器製造商解釋爲允許這種行爲。 –

1

你沒有初始化你的雙打,你確定他們總是有價值嗎?
我發現調試中未初始化的變量總是0,但在發佈時它們幾乎可以做任何事情。

+0

我假設初始化在「'...'」中,OP表示這不是實際可重現的代碼。 – interjay

相關問題