2012-08-07 105 views
1

我在一個應用程序中有一個相當奇怪的錯誤,我設法縮小到這個簡單的測試用例。布爾值在調試模式下比在發佈模式下有所不同

protected void Page_Load(object sender, EventArgs e) 
{ 
    bool isHeightExceeded = IsHeightExceeded(10.16f, 127.15f); 
    lit.Text = isHeightExceeded.ToString(); 
} 

private bool IsHeightExceeded(float y, float height) 
{ 
    float nextHeight = y + height; 
    return (137.31f - nextHeight) < 0; 
} 

當我構建和調試模式下運行這個isHeightExceeded布爾是假的(如我所期望的),但是當我重建和在釋放模式運行,現在是真。

幕後發生了什麼事情?我猜測它與浮點精度有關,但不完全確定它是什麼。

任何幫助,將不勝感激。

+2

試圖清理並重建您的解決方案? – 2012-08-07 10:26:08

+0

打印結果137.31f - nextHeight並檢查。 – 2012-08-07 10:29:33

+0

與優化發佈版本中的代碼有關的事情可以優化計算結果,但通過無法做到這一點的調試步驟,也許呢? – podiluska 2012-08-07 10:31:15

回答

4

我懷疑在64位(或80位)計算10.16f + 127.15f的值,然後與137.31f進行比較......然而在釋放模式下計算該值,然後截斷爲32位,然後再截斷爲相比。基本上,當中間值不被鉗位到更小的精度時,您可以得到像這樣的結果。

如果這是一個問題,即可能意味着你不應該使用floatdouble入手 - 如果這些意思是精確值,使用decimal代替。

+0

謝謝,這是有道理的,聽起來可能是這樣 - 更改爲小數可以給出正確的結果。 – 2012-08-07 11:33:54

1

10.16 + 127.15正好等於137.31,這意味着(137.31f - nextHeight)理論值爲0

由於有參與數值運算,你可以在一個數值精度問題承擔。使用調試器時可能會以不同的方式處理此問題。這只是一個猜想,但我不會感到驚訝。

在任何情況下,您的代碼都需要更正以解決精確度錯誤,並使用自定義公差值(例如0.00001)來獲得可預測的結果給讀者和用戶。如果您不添加該容差,則該代碼可以正確工作,僅用於雙精度值,而不用於讀取它的人員。

+2

區別在於比Single.Epsilon更大。 '137.31f - nextHeight'產生'-3,814697265625E-06',而'Single.Epsilon'爲'1,401298E-45'。 epsilon的使用在這裏不會起到幫助作用,儘管這是一個很好的建議。 – 2012-08-07 10:33:49

+0

@DanielHilgarth我在想一個「手工製作」的epsilon,而不是Single.Epsilon。在我的生產代碼中,我使用這些手工製作的ε值通常爲1E-5或1E-6。我會編輯我的答案以避免混淆。 – 2012-08-07 10:35:42

相關問題