It is well known that comparing floats by == is usually a mistake. In a 3D-vector class (with float components X, Y, Z) i wrote, two vectors are considered equal if their distance is considered zero.
public override bool Equals(object obj) { if (obj == null) { return false; } if (GetType () != obj.GetType ()) { return false; } float d = DistSq ((Vec) obj); return IsConsideredZero (d); } public float DistSq(Vec p) { Vec d = this - p; return d.LengthSq (); } public float LengthSq() { return X * X + Y * Y + Z * Z; } private const float VEC_COMPARE_EPSILON_ABS = 1E-05f; public static bool IsConsideredZero(float f) { return Math.Abs (f) < VEC_COMPARE_EPSILON_ABS; }
So far, everything worked fine. However, now i’d like to get a hashcode of the vector. I can see that something like hash = (int)X^(int)Y^(int)Z is bound to fail.
The best i could come up with was:
public override int GetHashCode() { return 0; }
This, of course, kind of sucks. Is there any way to get a reasonable hashcode? NaNs and other special values are possible, but unlikely, in case that is important.
It’s impossible assuming you want to have the normal hashcode/equality properties:
The first rule is the problem – because if each value is deemed ‘equal’ to the next greater representable number, you end up with all numbers being equal. For instance, suppose a number is deemed equal to another they’re within 0.1:
0 equals 0.08 0.08 equals 0.16 0.16 equals 0.24
=> 0 equals 0.16 by the transitivity rule => 0 equals 0.24 by the transitivity rule
(etc)
If you ignore the transitivity rule, then you still (presumably) want ‘equal’ values to have equal hashcodes. This effectively enforces the transitivity rule – in the above example, 0 and 0.08 have to have equal hashcodes, as do 0 and 0.16. Therefore 0 and 0.16 have to have equal hashcodes, and so on. Therefore you can have no useful hashcode – it has to be a constant.