I am using a nativehashmap<float,bool> within a Job to compare against a float
if (hashMap.ContainsKey(xPosition))
{
//DO SOMETHING
Debug.Log($“FOUND KEY {xPosition}”)
}
This seems inconsistent. Even when logging out the results. Testing with three values in the hashmap, the logs shows only value of 78.6956 found of the three.
Here is log, using three values in hashmap - only the third value is matched…
(Sorry inserting image doesn’t work)
Is there a flaw in using floats for lookups? Any better suggestions to perform a potentially large lookup on a position in a Job?
Floating point numbers are inherently imprecise. Unless you’re comparing float constants, you can’t really expect two floats to compare equal or to produce the same hash code. Unity has Mathf.Approximately to compare floats that takes into account possible inaccuracies.
Note that all your numbers are printed with five decimal digits and are likely rounded for brevity. Try using value.ToString("G9"); to get all decimal digits. Likely, the two 78.6956 numbers you’re seeing aren’t actually identical.
Using floats as keys is tricky and not usually recommended. You could try rounding your numbers to the precision you need or map them to integers but then positions can still be actually very close but not considered identical (e.g. if you round to two decimals, 1.104 and 1.106 are closer than your rounding distance but still considered unequal, 1.10 != 1.11). I’d recommend looking up specialized spatial data structures and how to use them instead.
OK so yes I have discovered that the issue is using floats as keys doesn’t play nicely with rounding issues.
I thought strings, but ToString() and Mathf.Approximately are not available in a Job.
I am now storing and matching against an int of the float * 1000.
STORE: var intPosition = (int)(floatPosition * 1000f);
KEY TO LOOKUP: var intPosition = (int)(floatPosition * 1000f);
This intPosition is set as key and appears to be more reliable than floats, except the rounding using int() at both ends isn’t consistent either.
So I tried this:
STORE: var intPosition = Mathf.FloorToInt(floatPosition * 1000f);
KEY TO LOOKUP: var intPosition = (int)math.floor(floatPosition * 1000f);
(No FloorToInt() in Jobs)
Which gives me reliable results but the performance is now awful.
Any other ideas to keep performance and avoid rounding issues?