简体   繁体   中英

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?

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 .

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

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.

我将创建只读属性,将Real和Imaginary舍入到最接近的千分之一,然后在这些getter属性上执行equals和hashcode实现。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM