2016-06-07 193 views
-5

請在您認爲我在問同樣的N%問題之前先閱讀並請注意。比較浮點數

我正在一個項目中,我有更多的函數返回雙倍,它可能有一些是相同的,這是我的項目中的好東西,如果是真的,那麼我需要一個double比較看看是否相等。

我知道做一個平等比較if(x == y)不是一個聰明的事情,我們不需要說爲什麼,但我們可以檢查<>這是這個問題的一部分。

語言(標準)保證這一點,比較<>是100%嗎?

如果是的話,下面的程序可用於:

#include <stdio.h> 

int main(void){ 
    double x = 3.14; 
    double y = 3.14; 

    if(x < y || x > y){ 
     /* Are not Equal */ 
    }else{ 
     /* Are Equal, foo() will be called here\n" */ 
     foo(x, y); 
    } 
} 

是否foo(x, y);得到執行?因爲XY應該在這裏相等。

編輯: 這個問題並不尋求一種方法來比較兩個雙,這僅僅是我應該使用這一事實,或者我應該不使用,而不是<>==

+0

真的是選民嗎?你最好在開玩笑吧。 – Michi

+0

我認爲這是光滑的。投了票。 – nicomp

+0

@nicomp沒問題:) – Michi

回答

2

我知道,做一個平等的比較if(x == y)是不是一個聰明的事

這根本不對。根據具體問題,做正確的事或做錯事是可能的。

if (x < y || x > y) 

這恰好保證了同樣的效果作爲

if (x != y) 

if (x == y) 

當一個是錯誤的相反的效果,另一種是錯了。當一個人是對的,另一個人也是對的。使用<>符號而不是==!=寫入相等條件並不會突然變得更加智能。


[1]除了其中一個操作數是NaN時。

+0

這是一個很好的答案。 – Michi

-2
#include <stdio.h> 

int main(void){ 
double x = 3.14; 
double y = 3.14; 

if(x < y || x > y){ 
    /* Are not Equal */ 
}else{ 
    /* Are Equal, foo() will be called here\n" */ 
    printf("yes"); 
    } 
} 

版畫是

+1

真的嗎?你甚至讀過我的問題......還是隻讀了一部分? – Michi

+1

我的意思是技術上他是正確的。它打印是;) – gbtimmon

+0

這是不正確的。 'x'和'y'不一定要達到'else'語句。相反,他們中的一個或兩個可以是「NAN」。 – EOF

1

如果要分數相等,則必須使用epsilon比較(即檢查數字是否在特定閾值內彼此足夠接近),或者非常小心地使用某些定點算術以避免舍入錯誤。

是的,同樣的問題已經被問的次數超過必要的:

你需要做更多的閱讀到的比較是如何工作的,特別爲什麼浮點平等不起作用。 (對於算術類型[當沒有像NaN那樣的特殊值時],!(x > y || y > x)將始終與x == y相同。實際上,大多數編譯器會優化x < y || x > yx != y) ,而是因爲舍入錯誤首先是浮點操作的基本部分。 x == y確實可以用於浮點類型,並且您可以自由地進行操作。在你進行任何算術運算並且想要比較它們之後,它就成了一個問題,因爲舍入誤差會做什麼是不可預測的。

所以基本上,是的。除非你真的對雙打做任何事情,否則比較平等。如果您只是將它們用作索引或類似的東西,只要您知道將它們分配給相同的值就不會有問題。使用布爾型身份不會使您從浮點數的基本功能中解脫出來。

+0

我從來沒有要求做比較的方法,我問的是,如果我可以/應該使用** < > **而不是** == **,但是它發生了,在這裏我們閱讀並理解我們想要的而不是什麼OP問 – Michi

+0

我不明白你的意思。當然你可以使用< and >而不是==,但是如果按照定義做同樣的事情,那你爲什麼要這樣做? – Taywee

+0

這個問題是一個很大的錯誤。我無法刪除它。我以任何方式投票回答你的答案。 – Michi

1

首先,你的條件是有點關閉。要檢查非平等想要

(x < y || y < x) 

(x < y || y > x) 

剛剛檢查同樣的事情兩次,含義X <Ÿ回來爲假。

忽略小問題:

是> <應在100%它幾乎總是一樣的==。唯一的區別是與Nan有不同的行爲。但它不能解決你的問題。

這是一個非常人爲的例子。

#include <stdio.h> 

void foo(double x, double y){ 
    printf("OK a:%f, b:%f\n",x,y); 
} 

void bar(double x, double y){ 
    printf("BAD a:%f, b:%f\n",x,y); 
} 

int main(void){ 

    double x = 3.14; 
    double y = 3.14; 


    if(x < y || y < x){ 
     /* Are not Equal */ 
     bar(x, y); 
    }else{ 
     /* Are Equal, foo() will be called here\n" */ 
     foo(x, y); 
    } 

    for(int i = 0; i < 1000; i++) { 
     y = y + 0.1; 
    } 

    x = x + 100; 

    if(x < y || y < x){ 
     bar(x, y); 
    }else{ 
     /* Are Equal, foo() will be called here\n" */ 
     foo(x, y); 
    } 
} 

這裏是你輸出(暗示其BAD)

我知道雙平等
$ ./a.exe 
OK a:3.140000, b:3.140000 
BAD a:103.140000, b:103.140000 

最佳做法是一些小量內檢查有沒有親近,

eps = 0.00000000001 

if(abs(x - y) < eps) { 
    printf("EQUAL!"); 
} 
1

一些他們是一樣的...如果是真的,那麼我需要一個雙重比較,看看是否相等。

OP在質疑測試FP相等性的兩種不同方法,並且懷疑它們是否在功能上相似。

除了也許NaN時,其不能很好地被C所定義,(但由IEEE 754明確定義的),既比較是相似但失敗圓錐形等價測試。

考慮這個double代碼:

if (a==b) { 
    double ai = 1.0/a; 
    double bi = 1.0/b; 
    printf("%d\n", ai == bi); 
} else { 
    printf("%d\n", 1); 
} 

是結果總是"1"?下面是一個例外(鼠標懸停看)

考慮a=0.0; b=-0.0。兩者彼此相等,但它們的倒數通常不相同。一個是正​​無窮,另一個是負無窮。

問題歸結爲如何你需要怎麼樣? NaN重要嗎?使用memcmp(&a, &b, sizeof a)肯定是一個強大的測試,可能在選擇的系統上太強大了FP編號可以具有相同的非零值,但是不同的編碼。如果這些差異很重要,或者僅僅是上述例外情況,那麼OP就是要做出決定的。


爲了測試,如果2個不同的代碼/功能進行了產生相同binary64結果,考​​慮等級其Unit-in-the-Last-Place差。像下面這樣:比較unsigned long long ULP_diff()與0,1或2.取決於你的容錯。

// not highly portable 
#include <assert.h> 
unsigned long long ULP(double x) { 
    union { 
    double d; 
    unsigned long long ull; 
    } u; 
    assert(sizeof(double) == sizeof(unsigned long long)); 
    u.d = x; 
    if (u.ull & 0x8000000000000000) { 
    u.ull ^= 0x8000000000000000; 
    return 0x8000000000000000 - u.ull; 
    } 
    return u.ull + 0x8000000000000000; 
} 

unsigned long long ULP_diff(double x, double y) { 
    unsigned long ullx = ULP(x); 
    unsigned long ully = ULP(y); 
    if (x > y) return ullx - ully; 
    return ully - ullx; 
}