2012-09-25 66 views
0

我有一個平等和添加對象的問題,以字典忽略equals和GetHashCode和雙比較

class DoublePoint 
{ 
    public double X; 
    public double Y; 
    public double Z; 

    public DoublePoint(double x, double y, double z) 
    { 
     this.X = x; this.Y = y; this.Z = z; 
    } 

    public override bool Equals(object obj) 
    { 
     try 
     { 
      DoublePoint dPoint = obj as DoublePoint; 
      return this.X.IsEqualTo(dPoint.X) && this.Y.IsEqualTo(dPoint.Y) && this.Z.IsEqualTo(dPoint.Z); 
     } 
     catch 
     { 
      throw; 
     } 
    } 

    public override int GetHashCode() 
    { 
     return this.X.GetCode()^this.Y.GetCode()^this.Z.GetCode(); 
    } 
} 

static class extensions 
{ 
    static double Tolerance = 0.001; 
    public static bool IsEqualTo(this double d1, double d2) 
    { 
     return (d1 - d2) <= Tolerance; 
    } 

    public static int GetCode(this double d1) 
    { 
     byte[] data = BitConverter.GetBytes(d1); 
     int x = BitConverter.ToInt32(data, 0); 
     int y = BitConverter.ToInt32(data, 4); 
     return x^y; 
    } 
} 

,這裏是我的測試:

DoublePoint d1 = new DoublePoint(1.200, 2.3, 3.4); 
     DoublePoint d2 = new DoublePoint(1.2001, 2.3, 3.4); 
     DoublePoint d3 = new DoublePoint(1.200, 2.3, 3.4); 
     bool isEqual = d1.Equals(d2); // true here 


     Dictionary<DoublePoint, int> dict = new Dictionary<DoublePoint, int>(); 
     dict.Add(d1, 1); 
     dict.Add(d2, 2); // successful, d2 is also added but d2 is equal to d1 
     dict.Add(d3, 3); // Error! since we have d1 already in dictionary 

有了這個,

  1. 當我添加相同的(具有一定寬容)的雙點對象時,我可以將它們添加到字典中。如何限制這些對象。

  2. 是將雙數據類型與一些容差進行比較的正確方法。

請指教。

謝謝

+0

請用您正在開發的語言標記問題 - 您將得到更好的答案 – codebox

+0

您正在使用哪種語言? –

+0

C#語言。 。 。 – Harsha

回答

0

沒有與定義「相等」爲「足夠接近」的一個問題。這對於計算來說無疑是有用的,但是這種「相等」違反了傳遞性規則:對於Equals如果a.Equals(b) && b.Equals(c),則a.Equals(c)必須爲爲真(這顯然不是您的代碼的屬性)。

所以,IsEqualTo不幸的是不適合重新定義Equals

解決問題的可能方法有哪些? Equals必須拆分爲「等價」值的不相交組。我通常做以下事情:定義一個規則來從一個組中獲得「規範」值,所以如果兩個規範組代表相等,那麼兩個值是「相等的」。

簡單示例:僅爲雙值d讓我們將規範值定義爲Math.Floor(d)。所以這樣你有1.0等於1.1,0.9等於0.0,但是不等於等於1.0。這種方式並不理想(畢竟0.9不等於1.0,但等於0.0似乎是錯誤的),但至少是傳遞性規則是持有的。

專門針對你的情況可能是這樣:

class DoublePoint 
{ 
    public double X; 
    public double Y; 
    public double Z; 

    const double epsilon; 
    void GetCanonicalValues(out double x, out double y, out double z) 
    { 
     x = Math.Floor(X/epsilon) * epsilon; 
     y = Math.Floor(Y/epsilon) * epsilon; 
     z = Math.Floor(Z/epsilon) * epsilon; 
    } 

    public override bool Equals(object obj) 
    { 
     DoublePoint that = obj as DoublePoint; 
     if (that == null) 
      return false; 
     double x1, y1, z1, x2, y2, z2; 
     this.GetCanonicalValues(out x1, out x2, out z2); 
     that.GetCanonicalValues(out x1, out x2, out z2); 
     return (x1 == x2) && (y1 == y2) && (z1 == z2); // here we can compare 
    } 

    ... 

與您的代碼的另一個問題是,你的GetHashCode沒有與Equals一致:如果a.Equals(b)然後a.GetHashCode()必須等於b.GetHashCode()

您可以通過使用規範值,解決這個還有:

當心的Equals行爲可能會爲您的需求不可接受的 - 那麼你就需要確保傳遞一些其他的方式。