tags:

views:

585

answers:

5

I am trying to create a quick hashcode function for a complex number class (a + bi) in C#.

I have seen repeatedly the a.GetHashcode()^b.GetHashCode() method. But this will give the same hashcode for (a,b) and (b,a).

Are there any standard algorithm to do this and are there any functions in the .Net framework to help?

A: 

Why don't you take the inverse of b e.g.

newB = b == 0 ? 0 : 1 / b;
Daniel A. White
+8  A: 

What about this:

(a.GetHashcode() + b).GetHashcode()

Gives you a different code for (a,b) and (b,a) plus it's not really that fancy.

Welbog
nice and clean - I likes it
annakata
It's not always correct.For Int32s, x.GetHashCode() just returns x.So (a.GetHasCode() + b).GetHashCode() is just a + b.
hwiechers
In the case when a and b are Int32.
hwiechers
+2  A: 

Here's a possible approach that takes into account order. (The second method is defined as an extension method.)

public int GetHashCode()
{
    return a.GetHashcode() ^ b.GetHashcode().RotateLeft(16);
}

public static uint RotateLeft(this uint value, int count)
{
    return (value << count) | (value >> (32 - count))
}

It would certainly be interesting to see how the Complex class of .NET 4.0 does it.

Noldorin
+11  A: 

My normal way of creating a hashcode for an arbitrary set of hashable items:

int hash = 23;
hash = hash * 31 + item1Hash;
hash = hash * 31 + item2Hash;
hash = hash * 31 + item3Hash;
hash = hash * 31 + item4Hash;
hash = hash * 31 + item5Hash;
// etc

In your case item1Hash could just be a, and item2Hash could just be b.

The values of 23 and 31 are relatively unimportant, so long as they're primes (or at least coprime).

Obviously there will still be collisions, but you don't run into the normal nasty problems of:

hash(a, a) == hash(b, b)
hash(a, b) == hash(b, a)

If you know more about what the real values of a and b are likely to be you can probably do better, but this is a good initial implementation which is easy to remember and implement. Note that if there's any chance that you'll build the assembly with "check for arithmetic overflow/underflow" ticked, you should put it all in an unchecked block. (Overflow is fine for this algorithm.)

Jon Skeet
"so long as they're primes (or at least coprime)" - I'd have thought that the initial state can be anything (if multiples of 31 are bad, then what happens when you hit such a value by chance part way through the calculation?). Then the multiplier just needs to be odd (to avoid early values having no effect on the low bits of the result). And not 1, to avoid commutativity. Am I completely missing the point?
Steve Jessop
I wouldn't like to say I've followed the logic for why the numbers should be co-prime - but that's the advice I've always seen given for this pattern by people wiser than myself (such as Josh Bloch).
Jon Skeet
Steve Jessop
+1  A: 

One standard way is this:

hashcode = 23
hashcode = (hashcode * 37) + v1
hashcode = (hashcode * 37) + v2

23 and 37 are coprime, but you can use other numbers as well.

Lasse V. Karlsen