2013-04-23 115 views
0

我在寫一個數字代碼,需要在雙精度數字之間進行廣泛的(也可能是快速的)比較。我比較兩個數字A和B的解決方案包括將A移到左邊(或右邊),並檢查結果是否比B更大(或更小)。如果是,則兩個雙打相同。 (需要對負數或零數字進行額外的編碼)。簡單的比較雙數的方法

這是比較功能:

#define S_ 
inline double s_l (double x){ 
    if(x>0){return 0.999999999*x;} 
    else if(x<0){return 1.00000001*x;} 
    else {return x-0.000000000001;} 
} 
inline double s_r (double x){ 
    if(x>0){return 1.00000001*x;} 
    else if(x<0){return 0.999999999*x;} 
    else{return x+0.000000000001;} 
} 
inline bool s_equal (double x,double y){ 
    if(x==y){return true;} 
    else if(x<y && s_r(x)>y){return true;} 
    else if(x>y && s_l(x)<y){return true;} 
    else{return false;} 
} 
#endif 

由於這是蒙特卡洛算法和s_equal(X,Y)的部分被稱爲數百萬次,我不知道是否有任何更好或更快地碼這在簡單的層面上是可以理解的。

+2

我喜歡abs((x-y)/ x)<1.0e-10 – 2013-04-23 23:33:21

+0

「幾乎相等」是一種先進的技術,不應該輕易進行。例如,如果'a'幾乎等於'b'且'b'幾乎等於'c',那麼'a'幾乎等於'c'。這可能會導致意想不到的併發症。 – 2013-04-24 00:39:44

+0

@brianbeuning考慮發佈這個答案。它與所提出的算法非常接近匹配,並且通過消除所有分支,它應該比所呈現的快得多。 – 2013-04-24 03:30:40

回答

0

我做一些像abs((x-y)/ x)< 1.0e-10。

如果兩個值都很大或很小,則需要用x除。

+0

感謝您的回覆!我想到了這種實現,但意識到它可能是危險的:1)當x爲0時,它會給NaN 2)當y爲0時,lhs等於1,不管x如何接近於0。解決方案中的'abs'對我來說似乎很自然,以便擺脫許多if語句,但將0附近的數字處理並不明顯。你有沒有想過這個問題?你是如何解決它的? – Ale 2013-04-24 19:42:45

+0

abs(((x == 0.0)?y:((y == 0.0)?x:(x-y)/ x)))<1.0e-10 – 2013-04-24 23:35:51

0

如果您使用的是C++ 11,那麼你可以使用新的math庫函數,如:

bool isgreater(float x, float y)

更多的文檔上std::isgreater就可以了here

否則,總是會有is_equal的提升。此外,SO已經有一堆相關的問題(不確定是否相同),如here,herehere

+0

謝謝。我不確定這是否解決了我的問題。我試圖找到isgreater或is_equal的定義,並且無法看到它們是否進行epsilon比較,如果是的話,以及哪個精度。關於其他線程,我確實搜索了它們,但發現大部分討論都是關於「固定」epsilon與abs(xy)<ε的比較,我認爲這是錯誤的... – Ale 2013-04-24 20:02:12

+1

@Ale http:// www。 boost.org/doc/libs/1_36_0/libs/test/doc/html/utf/testing-tools/floating_point_comparison.html – Jeff 2014-08-06 12:52:23

0

我驚訝地發現,通過避免所有的雙精度計算一個顯著加速:

#define S_L(x) (x)+((x)<0?1024:-1024) 
#define S_R(x) (x)+((x)<0?-1024:1024) 
#define S_EQUAL(x,y) (S_L(x)<(y) && S_R(x)>(y)) 

double foo;                  
double bar;                  
long *pfoo;                  
long *pbar;                  

pfoo = (long*)&foo;                
pbar = (long*)&bar;   

double result1 = S_R(*pfoo); 
double result2 = S_L(*pbar); 
bool result3 = S_EQUAL(*pfoo, *pbar); 

(在測試中,我手術-1M和1M之間隨機生成的雙打,執行每個操作100M次。與對於每次迭代不同的輸入的每個操作是在一個獨立的循環定時,比較系統時間 - 未壁倍包含隨機數的循環開銷和產生,該溶液爲約25%的速度)

的詞。的警告:這裏有很多依賴關係硬件,雙打的範圍,優化器的行爲等等等等。當你開始猜測你的編譯器時,這樣的缺陷是司空見慣的。我很震驚地看到這對我來說有多快,因爲我總是被告知整數和浮點單元在硬件上保持如此分離以致於從一個位到另一個位的傳輸總是需要硬件內存操作。誰知道這會對你有多好。

你可能需要玩一些神奇的數字(1024s)才能讓它處理你想要的東西 - 如果它是可能的話。

+0

謝謝。這是一個有趣的建議,但嚇人。代碼必須是可移植的並且由社區中的任何人編譯。我寧願犧牲一些速度來減少錯誤發生的機率! – Ale 2013-04-24 20:30:36