float adds decimal points over time

Hello, I have this script that is supposed to instantiate an object 10 times, every time 1.74 units up.
The problem is that it isn’t 1.74 every time, but something a little bit different, so the objects spawn on those y cordinates:

  • -17.4

  • -15.66

  • -13.92

  • -12.18

  • -10.44

  • -8.700001 (Here it starts getting weird, by adding 0.000001)

  • -6.960001

  • -5.220001

  • -3.480001

  • -1.740001

  • -1.192093e-06 (Here it is not 0, so I can not check on the IF statement)

       var posY : float = -17.4;
     var posX : int = 0;
     for(var i : int = 0; i <= 10; i++)
     {
     	if(posY == 0)
     	{
     		continue;
     		Debug.Log("Never goes here");
     	}
     	inst = Instantiate(par, Vector3(posX, posY, transform.position.z), transform.rotation);
     	posX ++;
     	posY += 1.74;
     }
    

Hi there

I answered a similar question here earlier:

Basically, floating point numbers are simply not accurate and there’s no way around this. Remember that internally they’re stored as binary values, so it’s entirely possible there won’t be a precise representation for -17.4. What you’re seeing is a very gradual drift, which is expected behaviour. It’s probably insignficant from the point of what the user sees, but precise comparisons often don’t work.

The most common way of correcting your code would be:

//check the absolute (i.e. postive) value of posY is almost exactly 0
if(Mathf.Abs(posY) <= 0.00001f)
         {
             continue;
             Debug.Log("Never goes here");
         }

Typically its best to avoid situations in which you need to compare a floating point numbers in this way, but when you have to do it, that’s the best approach to use.

Note that a more reliable way to write your code might be:

     var startPosY : float = -17.4;
     for(var i : int = 0; i <= 10; i++)
     {
         var posX : int = i;
         var posY : float = startPosY + i*1.74;

         if(Mathf.Abs(posY) < 0.00001)
         {
             continue;
             Debug.Log("Never goes here");
         }
         inst = Instantiate(par, Vector3(posX, posY, transform.position.z), transform.rotation);
     }

(sorry if that doesn’t compile - I’m a c# guy!)

By avoiding repeated additions that gradually get less accurate, I’ve ensured in this example that my numbers won’t drift. There will still be inaccuracies, but they won’t gradually get higher and higher and higher. I’m not entirely clear why you need the if statement at all, but maybe you just added it as an example?

Hope that helps

-Chris

Although the other answer will probably work, I’ll add this one, as the docs specify it as the way to check for float equality (Which is what you are trying to do)…

Use Mathf.Approximately instead of ==.

Like so: (ps. I believe adding your log after continue, should actually give you the warning in the console that it will never be called). as continue will skip it and continue with the next loop iteration :wink:

if (Mathf.Approximately(posY, 0))
{
    Debug.Log("does go here");
    continue;
    Debug.Log("Never goes here");
}