2016-07-29 73 views
2

我知道比較兩個doubles有問題,如果它們是從不同的計算中獲得的。但是,如果其中一個是另一個的副本(價值),這是否也適用。以下幾行解釋了這種情況。如果我有這樣的)問題,比較float和它的副本

double a,b; 
a=randdouble();/*some double value*/ 
b=a; 

然後,

Q1是比較a==b始終保證在C編譯器的情況下返回true(我有gcc 6.1.1)? Q2)如果我使用malloc在堆內存中分配變量ab,那麼上述答案是否保持不變?

Q3)請問上述答案仍然是相同的,如果我有一個Java編譯器(我使用Open JDK 1.7.0)與ofcourse必要的語法改變取代C編譯器。

編輯1:數字ab!= NaN

+0

1)否,2)是,3)是 –

+0

@EugeneSh。爲什麼'b = a'不會導致'b == a'成立。這是內存或寄存器的直接副本。 –

+0

@JoshSanford問題是關於*保證*。 –

回答

3

Q1:比較不保證評估爲true,原因很簡單,那NaN比較不等於本身。也可能有其他情況,但NaN是一個明顯的反例。第二季度:變量駐留在內存中沒有什麼不同。

問題3:我希望Java的行爲類似。

這種特殊情況之外,我認爲標準沒有作出這樣的保證:

設想一個ABI其中double表達式求值和值與80位精度(英特爾80x87堆棧)返回,但64存儲位IEEE-754雙打。即使randdouble()被定義爲返回double,而不是long double,其返回值可能比存儲在ab中的值更精確。根據編譯器如何優化randdouble()函數調用和比較a == b之間的各種表達式,它可能最終將80位精確返回值與通過轉換爲64位並返回80位而獲得的近親表達式進行比較。如果轉換中丟失了精度,比較將會失敗。我會嘗試從標準中找到適當的參考來支持這一點,但似乎是合理的,儘管ab是局部變量還是存儲在堆中可能會影響執行的轉換順序,但它仍會生病修改爲承擔任何一種或其他情況的擔保。

+0

我正在對'NaN'的存在進行故障安全檢查。我會更新關於'NaN'不存在的問題。你能相應地更新你的答案嗎? – Abhinav

+0

您所做的檢查不會改變事實。 –

+0

@EugeneSh。那個怎麼樣? 'pseudoRandom'生成器能產生一個'NaN'嗎? – Abhinav

2

作爲另一個答案,說NaN總是保證不同。這是IEEE-754浮點標準的定義。 C和Java都將它用於浮點和雙位表示,因此將NaN視爲不同。

a=Double.NaN; 
b=a; 

if (a==b) // <--- comparison will fail. 

但是對於比較將根據該值的IEEE-754位模式表現的所有其他值。如果兩個變量的比特表示是相同的,那麼比較結果就會成立。

因此,對於使用randdouble()的示例,您比較a == b將始終產生true,因爲您從字面上將位表示從a複製到b的賦值中(假設randdouble()永遠不會返回NaN)。

這就是說......你不應該依賴代碼中浮點值的精確比較。你的比較值很難通過直接分配來得到,就像我們這裏的小例子那樣。他們通常是通過一些計算得出的。比較的每一方通常都是通過一系列不同的計算得出的。由於IEEE-754限制固有的累積誤差,計算結果在位表示中經常會產生稍微不同的結果。

因此,無論存儲位置如何,存儲器位置都不重要,因爲位模式是相同的。在C或Java(或使用IEEE-754浮點表示的任何其他語言)之間,它也不會有問題。

+1

是否保證賦值運算符正在產生精確的位拷貝?是否保證比較操作總是返回true,以防精確位副本(帶有NaN異常)?我不這麼認爲,但會尋找參考。 –

+0

@EugeneSh。我認爲這是我困境的癥結所在。賦值運算符是否產生精確的位拷貝。 – Abhinav

+0

我認爲你不應該依賴這個。如果你真的想做一個對象的確切副本並逐位比較,使用'memcpy'和'memcmp'。我可能在這裏錯了,雖然,因爲我沒有找到很好的參考。 –