Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 977
Timo Willemsen Avatar asked Apr 18 '11 13:04

Timo Willemsen


3 Answers

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.

like image 69
Michael Borgwardt Avatar answered Sep 22 '22 01:09

Michael Borgwardt


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

like image 45
Elalfer Avatar answered Sep 22 '22 01:09

Elalfer


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.

like image 27
Carra Avatar answered Sep 23 '22 01:09

Carra