關於期望由單獨計算生成的兩個浮點數完全相等的危險已經有很多問題和解答,因爲浮點數不是實數。這個問題是而不是關於正確性依賴於平等檢查,這是關於基於它的緩存。用於緩存昂貴計算的浮點平等
想象一下,你有這樣的代碼:
if(myfloat != _last_float) {
refresh_expensive_computation(myfloat);
_last_float = myfloat;
}
在這種情況下,相等比較純粹的存在是爲了避免做重複的工作。如果輸入保持不變,我們將避免再次進行昂貴的計算(我們假設昂貴的函數是確定性的,並且沒有其它輸入發生改變)。
如果兩者真的相等(意思是說,如果我們可以用實數而不是浮點來計算),但是錯誤地發現它們不是,最糟糕的情況是我們會冗餘地執行昂貴的計算,但是我們的程序的答案仍然是正確的。 AFAIK如果計算是在比浮點的存儲器表示更寬的寄存器中完成的(例如,在80位fp寄存器被啓用時在32位x86上),並且在轉換爲它們發生的存儲器表示之後,它們只能錯誤地比較相等都是按位平等的。在這種情況下,差異必須超出內存表示的精度,這必須低於對我來說很重要的比較,因爲否則我會使用更寬的類型,如double。
所以我要斷言浮點平等的使用是安全的。所以第一個問題是,我錯了嗎?其次,如果我們假設它是安全的,我想避免錯誤地返回true,因爲它會導致昂貴的計算。在寄存器比寄存器表示更寬的機器上避免這種情況的一種方法是使用memcmp來強制它比較內存表示(對於NaN,語義不會完全相同,現在將與NaN中的完全相同的按位實例本身,但是對於緩存來說這是一種改進,或者對於+0和-0來說,但是這可能是特殊的)。然而,memcmp將比寄存器中的浮點比較慢。有沒有一種方法可以檢測平臺何時具有更寬的寄存器,因此我可以#ifdef或類似的方式在安全的平臺上獲得優化的實現?
你怎麼知道緩存的值是否正確,而無需進行計算來弄清楚它應該是什麼? – Dmitri
對不起,緩存的float應該被稱爲last float,編輯得更清晰。我們看到輸入是否在變化。我們假設相同的輸入產生相同的輸出。 –
好的...如果您要保存一個輸入/輸出對,並且在新輸入與保存的輸入相匹配時使用保存的輸出值,那麼只要給定輸入中只有一個輸出值有效,就應該沒問題。 ..雖然這似乎很明顯,所以我很驚訝你會問。 – Dmitri