-2

I have a strange problem. My code checks the value of Vector2 and returns an enum based on that value. But I noticed that sometimes it gives really strange results, even if Vector2 values are the same few times in a row, it's able to give different results.

protected eMove TranslateGridMove (Vector2 move) 
{
    if (move.x == 1f)
    {
        Debug.Log("Executing move " + move);
        return eMove.RIGHT;
    }
    else if (move.x == -1f)
    {
        Debug.Log("Executing move " + move);
        return eMove.LEFT;
    }
    else if (move.y == 1f)
    {
        Debug.Log("Executing move " + move);
        return eMove.UP;
    }
    else if (move.y == -1f)
    {
        Debug.Log("Executing move " + move);
        return eMove.DOWN;
    }
    else
    {
        Debug.LogWarning("PATH FINDING ERROR: CANNOT EXECUTE MOVE " + move);
        return eMove.NONE;
    }
}

Results:

Executing move (0.0, -1.0)

and sometimes :

PATH FINDING ERROR: CANNOT EXECUTE MOVE (0.0, -1.0)

Why sometimes it works as expected and sometimes not?

Martin Zikmund
  • 38,440
  • 7
  • 70
  • 91
  • https://docs.unity3d.com/ScriptReference/Mathf.Approximately.html – Evan Trimboli Jul 19 '20 at 22:52
  • 1
    Floating-point numbers are not infinitely precise, you will get rounding errors when you do calculations with floating-point numbers. If there's a rounding error, it can easily happen that your float is very close to but not exactly 1.0. See: [comparing float/double values using == operator](https://stackoverflow.com/questions/6837007/comparing-float-double-values-using-operator) – Jesper Jul 19 '20 at 22:53
  • 1
    I wouldn't be doing equality on floating point numbers unless I explicitly rounded or truncated to a specified number of digits. – radarbob Jul 19 '20 at 22:55
  • Is there no FAQ/Community Wiki about this? – CompuChip Jul 19 '20 at 23:04
  • 1
    @CompuChip: as if new users ever would read an FAQ or wiki. But yes, this question has been asked and answered dozens of times at least already, if not hundreds. A reasonably diligent search would've turned up plenty of info on the topic. Searching is another thing that new users almost never do either. – Peter Duniho Jul 19 '20 at 23:15
  • It would actually be nice to create a newbie readable version of the classic *What Every Computer Scientist Should Know About Floating-Point Arithmetic* https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html. And then make it easy to put in a comment (say something like [fpmath]). It's such a FAQ – Flydog57 Jul 19 '20 at 23:55
  • https://floating-point-gui.de/ also explains it quite well. – Franz Gleichmann Jul 20 '20 at 04:59
  • @Flydog57 that was exactly the reason for my comment :-) – CompuChip Jul 20 '20 at 08:20

2 Answers2

2

You should never do == comparison of floating-point types, because of how they are represented in memory. In short, the values are calculated using exponentials of two and most "nice" 10-base values actually cannot be represented accurately. You can look up more detailed information on this for example here.

Instead of a == b comparison, it is better to do something like

if (Math.Abs(a - b) < TOLERANCE)

Where TOLERANCE is some small constant, for example, 0.0001.

Martin Zikmund
  • 38,440
  • 7
  • 70
  • 91
  • 2
    _"most "nice" 10-base values actually cannot be represented accurately"_ -- this part of your answer is very misleading because it implies that an integer having magnitude of 1 would be one of these "nice" values that "cannot be represented accurately". In fact, the problem here has nearly nothing to do with the actual representation of the number. It's the simple limitation of _precision_ that prevents the equality comparisons from working. – Peter Duniho Jul 19 '20 at 23:17
  • 2
    You should rather use Unity built-in [`Mathf.Approximately(a, b)`](https://docs.unity3d.com/ScriptReference/Mathf.Approximately.html) instead! It basically equals [`Mathf.Abs(a - b) <= Mathf.Epsilon`](https://docs.unity3d.com/ScriptReference/Mathf.Epsilon.html). – derHugo Jul 20 '20 at 08:09
-6

In C# literal value 1.0 has default type double. Try to change in comparison expressions 1f to 1d.