1

平等と辞書へのオブジェクトの追加に問題があります

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. double データ型をある程度の許容範囲で比較する正しい方法です。

ご意見をお聞かせください。

ありがとうございました

4

1 に答える 1

1

「等しい」を「十分に近い」と定義することには問題があります。間違いなく計算に役立ちますが、そのような「等しい」は推移性のルールに違反します: for Equalsif a.Equals(b) && b.Equals(c), then true を保持するa.Equals(c) 必要があります (これは明らかにコードのプロパティではありません)。

残念ながら、IsEqualToは再定義には適していませんEquals

問題を解決するために可能な方法は何ですか? Equals「同等の」値のばらばらなグループに分割する必要があります。私は通常、次のことを行います。グループから「正規」値を取得するルールを定義します。したがって、正規グループの代表が等しい場合、2 つの値は「等しく」なります。

簡単な例: double 値の場合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
    }

    ...

コードのもう 1 つの問題は、 yourが: if then must equal とGetHashCode一致していないことです。Equalsa.Equals(b)a.GetHashCode() b.GetHashCode()

正規値を使用してこれを解決することもできます。

    public override int GetHashCode()
    {
        double x, y, z;
        GetCanonicalValues(out x, out y, out z);
        return x.GetHashCode() ^ y.GetHashCode() ^ z.GetCode();
    }
}

の動作がEqualsニーズに合わない場合があることに注意してください。その場合は、他の方法で推移性を確保する必要があります。

于 2013-03-03T13:23:20.443 に答える