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; }
Floats
Have a limited precision
Are stored as binary numbers on computers
Due to being binary 1.74 has to be converted from decimal. There's no exact way to represent 74/100 in binary so the float just rounds the number to a few significant figures. These errors accumulate and can become obvious.
The is analagous to how you would represent 1/3 in decimal. If you could have 3 significant figures you would use 0.333. Going down from 1 to 0 your values would be 1.000, 0.667, 0.334, 0.001.
There are very few situation where you should be comparing floats using ==.
You could use ints for adding up the posY (start with -1740 and adding 174) and divide it by 100 only when actually instantiating the gameobject (something like (float)posY / 100 ... I don't know for js) and see if this is working better.
Answer by wibble82 · Dec 07, 2015 at 03:03 PM
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
Thanks!
I found a workaround! I used:
posY = System.$$anonymous$$ath.Round(posY, 2)
Heheh - I guess that works, though the careful programmer in me disprove :) Lets hope you never want to increment by 1.745 every frame!
Answer by troien · Dec 07, 2015 at 03:33 PM
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 ;)
if (Mathf.Approximately(posY, 0))
{
Debug.Log("does go here");
continue;
Debug.Log("Never goes here");
}
Your answer
Follow this Question
Related Questions
Angular Velocity to zero 0 Answers
How to get type double to vector3? 0 Answers
Float without comma 1 Answer