2012-02-06 53 views
2

我想要一個set<double> S;並插入一些雙打。但我想要集合考慮1.0000001 == 1.0000000(比較使用epsilon的雙打)(我的意思是如果我插入兩個數字的集合,set.size()應該等於一)。我知道如何通過運營商()(比較)來設定的,但我不知道如何傳遞給函數:傳遞operator ==來設置C++

const double eps = 1e-8; 
bool operator==(double a, double b) 
{ 
    return abs(a - b) < eps; 
} 

設定的。

P.S:謝謝Sid。 @Sid:我發現:operator ==沒有被std :: set使用。元素a和b被認爲是相等的iff!(a < b)& &!(b < a)。

+2

我不是C++專家,但我非常肯定,您需要使用傳遞關係作爲集合的比較。你的'operator =='不是傳遞的。 – 2012-02-06 18:34:15

+0

@Complicatedseebio這兩個數字中的哪一個並不重要。重要的是他們中的一個在場。 – Farzam 2012-02-06 18:37:23

+2

可能的重複[如何初始化一個std :: set比較器?](http://stackoverflow.com/questions/3782702/how-do-i-initialize-a-stdset-comparator) – 2012-02-06 18:39:13

回答

2

如果你有比較功能,那麼爲什麼還需要運營商==?看看下面的線程。

std::set with user defined type, how to ensure no duplicates

Mehrdad's answer

+0

請參閱P.S我有一個問題 – Farzam 2012-02-06 18:52:26

+0

是的,這是真的。但是你可以在你的比較函數中控制這種行爲。例如,如果a = 1.0000000和b = 1.0000001,你可以檢查fabs(ab)是否小於1e-6(或者你想要的任何精度),那麼你返回一個假(即既不小於b也不小於b) a)因此告訴 a和b被認爲是相等的。 – Sid 2012-02-06 18:55:49

+0

由於'!comp(k1,k2)&&!comp(k2,k1)'不會定義一個等價關係,並且這種關係不是可傳遞的:'comp( k1,k2)&& comp(k2,k3)'即使'comp(k1,k3)'爲真也可以返回錯誤。 – 2012-02-06 18:59:40

-1
const double eps = 1e-8; 
bool compare(double a, double b) 
{ 
    return (abs(a - b) > eps) ? (a < b) : false; 
} 

set<int,bool(*)(double,double)> set (compare); 

struct Compare 
{ 
    bool operator()(double a, double b) const 
    { 
     return (abs(a - b) > eps) ? (a < b) : false; 
    } 
}; 

set<int,Compare> set; 
+1

Ahm,不應該比較函數定義一個「小於」關係,而不是「等於」? – 2012-02-06 18:38:47

+0

但是這個通過運算符<,我想通過運算符==。 – Farzam 2012-02-06 18:39:37

+0

@Farzam'std :: set'默認使用排序關係來命令它的元素,'std :: less'。它不測試相等性,但是依賴於定義等價關係的'!cmp(lhs,rhs)&&!cmp(rhs,lhs)'。 (其中提出的功能沒有。) – 2012-02-06 19:07:08

0

這似乎是一個壞主意。考慮數字爲1.0000000,1.0000001,1.0000002的情況。如果您先插入1.0000001,那麼其他號碼將不被允許添加到該集合中。如果先添加1.00000001.0000002,則可以稍後添加另一個。

此外,set使用operator<來定義它的關係,而不是相等。我看不到一種依賴epsilon的嚴格的弱順序編寫方式,它不會產生正確排序的容器。該容器依賴只需operator<或其他比較,並且沒有指定相等操作的方法。

更好的方法是隻使用正常的<比較,並在建立集合後進行後期處理,以清理不再需要的元素。如果您向我們提供有關真實問題的更多信息,您正試圖解決,我們可能會提供幫助。

+0

您可以使用'modf'(或者其他的東西)定義一組離散的範圍,然後在每個範圍內使用一個特徵元素進行比較。但你最後的建議可能會更好。 – 2012-02-06 19:04:56

1

去關閉的@Sid提供的鏈接,似乎(但良好或不明智的,它是),你可以通過定義比較操作如下做到這一點:

const double eps = 1e-8; 
bool less_than(double a, double b) 
{ 
    return a < b - eps; 
} 

bool greater_than(double a, double b) 
{ 
    return a > b + eps; 
} 
+0

它沒有定義等價關係,也不是傳遞的,所以它沒有定義嚴格的弱排序。 (這意味着使用它作爲'std :: set '的比較函數是未定義的行爲。) – 2012-02-06 19:02:30

0

請將詳細在你的示例代碼中。我認爲這是不完整的,以回答你的問題。

3

簡單的答案是,你不能,至少不那麼容易。你必須定義一個比較運算符,它定義了一個嚴格的弱排序。如果你有這樣的:

bool 
cmpDouble(double lhs, double rhs) 
{ 
    return abs(lhs - rhs) < eps 
     ? false 
     : lhs < rhs; 
} 

然後! (a < b) && ! (b < a)沒有定義等價 關係,所以主要的要求沒有得到滿足。

有可能使用類似:

bool 
cmpDouble(double lhs, double rhs) 
{ 
    double iLhs; 
    modf(1e8 * lhs, &iLhs); 
    double iRhs; 
    modf(1e8 * rhs, &iRhs); 
    return iLhs < iRhs; 
} 

但坦率地說,我懷疑,如果你加倍的源需要這種 類的事情,他們可能不適合在set存儲。

1

你需要量化你的雙打之前插入到集合中。

如果你在考慮範圍內的所有數字1.0000000 < = X < 1.0000002是相同的,前只需更換所有的數字在這個範圍內1.0000000 將它們插入到該集合。同樣適用於1.0000002 < = x < 1.0000004等

此方法避免了比較運算符和傳遞性的所有問題。