Timo Willemsen
Timo Willemsen

Reputation: 8857

Hashcode implementation double precision

I've asked a question about this class before, but here is one again.

I've created a Complex class:

 public class Complex
 {
        public double Real { get; set; }
        public double Imaginary { get; set; }
 }

And I'm implementing the Equals and the Hashcode functions, and the Equal function takes in account a certain precision. I use the following logic for that:

    public override bool Equals(object obj)
    {
        //Some default null checkint etc here, the next code is all that matters.
        return Math.Abs(complex.Imaginary - Imaginary) <= 0.00001 &&
            Math.Abs(complex.Real - Real)  <= 0.00001;
    }

Well this works, when the Imaginary and the Real part are really close to each other, it says they are the same.

Now I was trying to implement the HashCode function, I've used some examples John skeet used here, currently I have the following.

    public override int GetHashCode()
    {
        var hash = 17;
        hash = hash*23 + Real.GetHashCode();
        hash = hash*23 + Imaginary.GetHashCode();
        return hash;
    }

However, this does not take in account the certain precision I want to use. So basically the following two classes:

Complex1[Real = 1.123456; Imaginary = 1.123456]

Complex2[Real = 1.123457; Imaginary = 1.123457]

Are Equal but do not provide the same HashCode, how can I achieve that?

Upvotes: 5

Views: 2828

Answers (4)

Michael Borgwardt
Michael Borgwardt

Reputation: 346377

First of all, your Equals() implementation is broken. Read here to see why.

Second, such a "fuzzy equals" breaks the contract of Equals() (it's not transitive, for one thing), so using it with Hashtable will not work, no matter how you implement GetHashCode().

For this kind of thing, you really need a spatial index such as an R-Tree.

Upvotes: 6

Carra
Carra

Reputation: 17964

I see two simple options:

  • Use Decimal instead of double
  • Instead of using Real.GetHashCode, use Real.RoundTo6Ciphers().GetHashCode().

Then you'll have the same hashcode.

Upvotes: 1

Elalfer
Elalfer

Reputation: 5338

Just drop precision when you calculate the hash value.

public override int GetHashCode()
{
    var hash = 17;
    hash = hash*23 + Math.Round(Real, 5).GetHashCode();
    hash = hash*23 + Math.Round(Imaginary, 5).GetHashCode();
    return hash;
}

where 5 is you precision value

Upvotes: 2

maple_shaft
maple_shaft

Reputation: 10463

I would create read-only properties that round Real and Imaginary to the nearest hundred-thousandth and then do equals and hashcode implementations on those getter properties.

Upvotes: 0

Related Questions