Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

NativeHashmap Lookup issue

Discussion in 'Scripting' started by OJDee, Feb 4, 2021.

  1. OJDee

    OJDee

    Joined:
    Feb 11, 2014
    Posts:
    64
    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..

    https://www.dropbox.com/s/n4zo60rlz22uf0l/hashmap-lookup.jpg?dl=0
    (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?
     
    Last edited: Feb 4, 2021
  2. Adrian

    Adrian

    Joined:
    Apr 5, 2008
    Posts:
    1,051
    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.
     
  3. OJDee

    OJDee

    Joined:
    Feb 11, 2014
    Posts:
    64
    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?
     
    Last edited: Feb 4, 2021
  4. OJDee

    OJDee

    Joined:
    Feb 11, 2014
    Posts:
    64
    Seems something else was affecting performance.

    STORE: var intPosition = Mathf.FloorToInt(floatPosition * 1000f);
    KEY TO LOOKUP: var intPosition = (int)math.floor(floatPosition * 1000f);

    This appears to give reliable and performant results, tested up to 10k kv pairs in hashmap.