1

I'm overwriting the GetHashCode() Function for my Vector class. Its just contaning 3 floats X, Y, Z. I'm wondering whats the best way to do so.

public override int GetHashCode()
{
    var sum = X + 3 * Y + 5 * Z;
    return sum.GetHashCode();
}

I need this to quickly find a Vector in a big-Collection.

I don't want to just return X.GetHashCode() or so, because this would lead to too many equals checks for straight lines.

The problem with my current implementation is that, if the floats are really big I might get an integer overflow.

  • Is there a way to tell my compiler to just cut out any overflow?

  • Is there a better Solution?

Thanks in advance.

Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
Griizz
  • 155
  • 1
  • 12
  • You could use the `unchecked` keyword, and then combine the values. See [this question](https://stackoverflow.com/questions/263400/what-is-the-best-algorithm-for-an-overridden-system-object-gethashcode). – Neijwiert May 24 '19 at 07:55
  • @Neijwiert seems good to me feel free to write an answer :) – Griizz May 24 '19 at 08:00

2 Answers2

4

Is there a way to tell my compiler to just cut out any overflow?

Yes, you can use the unchecked keyword for that. As @kalimag pointed out, only integral values throw exceptions on overflow.

Is there a better Solution?

The proper way to combine hash values would be:

public override int GetHashCode()
{
    unchecked
    {
        int hash = 17;
        hash = hash * 23 + X.GetHashCode();
        hash = hash * 23 + Y.GetHashCode();
        hash = hash * 23 + Z.GetHashCode();

        return hash;
    }
}

See this question for explanation.

Neijwiert
  • 985
  • 6
  • 19
  • `float` and `double` never throw overflow exceptions, they turn into negative or positive infinity. `checked`/`unchecked` only affects primitive integer types. Calling `GetHashCode()` on each individual `float` is probably still a good idea though to improve the quality of the combined hash code. – kalimag May 24 '19 at 08:09
  • @kalimag you're right. But in this case the floats are converted to integral values and then do need to be unchecked for overflow. I edited the question to reflect your comment. – Neijwiert May 24 '19 at 08:17
3

Often, when we combine hash codes manually, we do it with xor:

public override int GetHashCode() =>
  X.GetHashCode() ^ Y.GetHashCode() ^ Z.GetHashCode();

See Why is XOR the default way to combine hashes? for details

xor never throws any exception. You can let .Net to combine for you:

public override int GetHashCode() => HashCode.Combine(X, Y, Z);
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
  • How is it a better solution when pairs with the same value get 0 hashcode? suppose we have x,y,z = 2 and x,y,z = 3. Both get hashcode 0. – Neijwiert May 24 '19 at 08:28
  • 1
    @Neijwiert: if `x.GetHashCode() == 0` and `y.GetHashCode() == 0` but `z.GetHashCode() == 2` or `3` we have `0 ^ 0 ^ 2 == 2` and `0 ^ 0 ^ 3 == 3`, you've probably mixed `^` and `&` – Dmitry Bychenko May 24 '19 at 08:31
  • 1
    @Neijwiert actually they would not. if x,y,z = 2 x^y=0 but x^y^z=2 again.It' a slim solution thats why i prefer it. Every solution will have overlap since we put 96 bits of data in 32 bits. I have no time to determ right now wich will perform better – Griizz May 24 '19 at 08:35
  • You're right, I forgot that after the first 2 it already turns to 0. It would however be a problem in case of a 2D vector though or anything with 2 fields. – Neijwiert May 24 '19 at 08:38