- Home /
Problem is not reproducible or outdated
Unity 2*10^-16 == 0 is true!!
I want to delete duplicates from a List of Vector3. I used the Distinct() function and it worked. However, Unity added a tiny number (for example, 2*10^-16) to some of its components and so, the Distinct() function doesn't detect the vectors as equal. Therefore, I tried doing a function by hand. When I compared the two numbers, it said that "2*10^-16 == 0" is true!! I've done some research and the only thing I've found is the .Approximately() function, and it does the opposite of what I want. How can I compare such a tiny number without Unity approximating it to zero??
Answer by troien · Jan 06, 2019 at 11:39 AM
I'm honestly not 100% sure what you want to do, because to me it sounds like you actually want to use the Approximatly() method in parts of your question, but then you state you want the opposite... So here are the options you have.
So, if you want to check if two vectors are exactly equal, you can use:
Vector3.Equals.
If you want to check if 2 vectors are practically equal. But might have very slight differences due to floating point inaccuracies. (This was the first google hit for me, google it yourself if it isn't clear enough)
Vector3.== operator (see link for example of what is considered equal)
If you are instead of comparing vectors, comparing individual floats, you can use Mathf.Approximately to compensate for float inaccuracies.
I'm sorry I didn't make myself clear, it's a bit complicated and I don't really know the exact source of the problem:
I create a List containing Vector3
Those Vector3 have the y = 0
I don't operate or manipulate them any further!
Some of those vectors are duplicated, so I use the "Distinct()" function to try to eli$$anonymous$$ate them
When I spawn an instance at those positions one of the instances will have y = 0 and the duplicate, y = 2*10^-16
Then, I placed an if statement before the "Instantiate":
if(y == 0){Instantiate(...);}
to try to eli$$anonymous$$ate the duplicates with y = 2*10^-16 - I hit play and there were the same duplicates, with y = 2*10^-16
(I already tried looping through all the vectors and setting their y to 0)
Therefore, I deduce that:
Either the engine is having issues comparing such tiny numbers and that, in this case, 2*10^(-16) == 0
Or the Instantiate function is having some issues with the coordinate y = 0
(Although I doubt it is the second option because otherwise, the "Distinct()" function would have eli$$anonymous$$ated the duplicates. So we can say there's a difference between the Vector3, which in the editor appears to be the y component)
So, what I want is to eli$$anonymous$$ate those duplicated vectors and the only difference they have in the editor (after exectution) is the y component.
Ok, so to better explain my answer :)
Either the engine is having issues comparing such tiny numbers and that, in this case, 2*10^(-16) == 0
This is not as much with the Unity engine, it is more a problem with floating points in general (Follow the link to the floating point inaccuracies in my original answer, explained pretty good there, point 3 in that accepted answer is probably the problem you are facing atm.), which is why the engine has certain helper methods (like $$anonymous$$athf.Approximate and the Vector3 == Vector3 operator) to make sure you can still do equal checks, even though after manipulation the float values are not 100% equal.
$$anonymous$$eaning that unity made these method return true on purpose, even though they are actually not equal, they are equal enough, in case of Vector3:
To allow for floating point inaccuracies, the two vectors are considered equal if the magnitude of their difference is less than 1e-5.
What I think is happening is that in this 'duplication of vectors' some maths are involved without realizing it ($$anonymous$$aybe scale or conversion from local to world when you retrieve it from a transform) $$anonymous$$eaning the duplicated values have a chance that the are not exactly the value you expect them to be. I always believed that just copying them should not change their value ever, but I'm not 100% sure on that one and I don't know where you copy them from/to and how you copy them. As getting or setting transform.position will probably involve maths.
As a general rule, I just never expect any floats to be an exact value.
Looking at the things you figured out I expect that the IEnumerable.Distinct is implemented to use .Equals ins$$anonymous$$d of the .== operator, meaning it won't see the 0 and 2*10^-16 as equal and include them both. $$anonymous$$aybe an easy fix would be to write your own Distinct and use the .== operator in there? Because properly 'fixing' float inaccuracy is impossible. And in most cases it doesn't matter because the difference is so small that you can't notice it.
Also, it shouldn't be a problem with just 0 and not just y, more numbers and axis can suffer from this, and to make it even more fun, 2 different machines can get 2 different results...
Follow this Question
Related Questions
Is it a good idea to check if a float isn't zero 3 Answers
Float subtracting in increments of 1 no matter what value it's subtracted by 0 Answers
Float check not returning the right value. 1 Answer
if get key and float bigger as 1 Answer
How do I remove floating point errors when setting rotations with an editor script!? 2 Answers