math.hash - float3 creates collision, int3 doesn't

Hello!

I worked on hashing map tile coodinates and found collisions with my approach.

Coordinates like 1000/0/1000 and -1000/0/-1000 results in the same hash.
newPos is a quantized float3 and the following doesn’t work like expected:
int hash = (int)math.hash(new float3(newPos));

This does work:
int hash = (int)math.hash(new int3(newPos));

Anyone able to explain this behaviour?

hashing floats is problematic but what does work well is convert to integers at a specific precision.

public static float ToFloat(this int i)
        {
            return i / 100f;
        }

        public static int ToInt(this float i)
        {
            return (int)(Math.Round(i * 100, 2));
        }

This has nothing to do with precision.
1/0/1 creates the same hash as -1/0/-1 with floats, ignoring the sign. I don’t get why it does that.

edit:
eh, reading the source code helps

/// <summary>Returns a uint hash code of a float3 vector.</summary>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static uint hash(float3 v)
        {
            return csum(asuint(v) * uint3(0x9B13B92Du, 0x4ABF0813u, 0x86068063u)) + 0xD75513F9u;
        }

float3 gets converted to uint. Somewhere in asuint or subsequent in asint the sign gets lost.

Is this intended behaviour?

I understand the problem I was just showing an alternative approach that doesn’t have this or other issues when hashing floats.

Never looked closely at this but it appears uint is an optimization. Maybe they just wanted to standardize on the lowest common denominator for hashing? As there is hashwide which works but returns a uint3. Which you can use as a key at the cost of some extra space.