- Home /
Vector3 == comparison efficiency and float precision
what is the error rate comparing Vector3's to be == ?
I seem to have about 20% of my objects missing when I compare to see if the objects are there, with : if (Vector3(X, Y, Z) == Vector3 (X, Y, Z)){ do something;}
I would prefer to compare them using integers/mathf.round, although there are many 1000ds compare, so I am concerned about speed. What is the the most efficient way to check many Vector3 == precisely?
here's a pic: if no tiles == expected terrain, make tile @ expected terrain... it's missing a line of tiles until spaceship position is updated.
Answer by aldonaletto · Feb 07, 2013 at 10:17 PM
Vector3 comparison must be based on distance: if the distance between two Vector3 is less than some predefined value, they are considered equal. This is exactly what Unity does when you compare two Vector3 (Vector3 == operator as implemented in Unity):
public static bool operator ==(Vector3 lhs, Vector3 rhs)
{
return Vector3.SqrMagnitude(lhs - rhs) < 9.99999944E-11f;
}
This function is called by Unity in the compiled code whenever you compare two Vector3 values, thus doing it yourself will not cause any loss in performance - for instance:
public bool V3Equal(Vector3 a, Vector3 b){
return Vector3.SqrMagnitude(a - b) < 0.0001;
}
This limit is equal to 0.1mm, very small but still one million times greater than the builtin limit.
My fault! We're comparing squared magnitude, thus this limit equals 0.01 m, or 1 cm as noticed by @higekun in the comments (for 0.1 mm the value should be 0.00000001). For other limits, follow @Bunny83's suggestion (also posted in the comments).
In practice, you should replace the Vector3 equality operators by a call to this function, like this:
if (posA == posB){ // < --- replace this...
...
if (V3Equal(posA, posB)){ // < -- with this
...
Interesting to learn that this is what Unity does under the hood.
Worth noting: you're comparing squared magnitude, not magnitude, so the threshold is actually 1cm not 0.1mm - fairly coarse.
@higekun: Well that's just basic math ;) The easiest way to define the threshold is to square the threshold manually. If you want 1 mm you just use (0.001 * 0.001) == 0.000001
Thanks guys! I forgot that I was comparing squared distances.
Answer by GerryM · Feb 07, 2013 at 09:52 PM
As the vector components are floats comparison for equality is kind of tricky. I'd use a helper function to test with some given precision. Something like:
public static bool AlmostEqual(Vector3 v1, Vector3 v2, float precision)
{
bool equal = true;
if (Mathf.Abs (v1.x - v2.x) > precision) equal = false;
if (Mathf.Abs (v1.y - v2.y) > precision) equal = false;
if (Mathf.Abs (v1.z - v2.z) > precision) equal = false;
return equal;
}
If that's too slow you can consider some optimization afterwards.
better
public static bool AlmostEqual(Vector3 v1, Vector3 v2, float precision) { if ($$anonymous$$athf.Abs(v1.x - v2.x) > precision) return false; if ($$anonymous$$athf.Abs(v1.y - v2.y) > precision) return false; if ($$anonymous$$athf.Abs(v1.z - v2.z) > precision) return false; return true; }
Answer by Dave-Carlile · Feb 07, 2013 at 09:56 PM
You can use the Mathf.Approximately function to test floating point values for "equality". You would have to test each vector component. Another method would be to subtract the two vectors and use Vector3.sqrMagnitude to test the length. That's potentially less efficient though.
The best way to check the performance is to write the code and check the performance.
Answer by marnsmith · Feb 07, 2013 at 11:40 PM
Floats are approximations, and all kinds of things can affect their actual value (release mode, platform, how they were derived)... so even if == sometimes works, it's generally not a good idea.
For vector comparisons, you can use something like this:
float d = Vector3.SqrMagnitude(a - b);
if (d > EPSILON) {
// something amazing
}
SqrMagnitude is faster than Magnitude since no square root is needed, but there are still a few multiplies involved.
If this is too slow, consider why you have so many comparisons to begin with. For example, it looks like you're using a grid structure: can you check for objects only in the local neighborhood by using grid coordinates (relative integers)? Can you use some other spatial data structure?
O$$anonymous$$G it was my fault, I left a modulo of 10 in a grid that was 12x12 and I must have spent 7 hours trying to solve an artefact further on in the code . i am a level 2 "fast" code writer now... ahem Sorry about that guys! Thank you for $$anonymous$$ching me about Vector3 precision and efficiency!
Answer by nsxdavid · Feb 16, 2014 at 10:22 PM
The Unity implementation of Vector3 == already accounts for "approximately equal". The documentaiton states:
This will also return true for vectors that are really close to being equal.
Further, there appears to be an undocumented public member:
public const float kEpsilon = 1e-005f;
One presumes that this constant is used for the "close enough" comparison.
Vector2 also have this feature.
I'm not sure why they're so intent on implementing their own compare function. It would be cleaner to pass over all the verts that are slightly off and snap them together so the unity compare picks them up.
@gtmacd I'm a bit late but I'm not sure I follow you. This is a problem with floating point calculation that's deeply ingrained in the way floating point works, any kind of snapping would be really bad for Unity, not to mention that a snapping algorithm can't be cheap.
Vector3 == does already account for "approximately equal" The exact implementation looks like this
return Sqr$$anonymous$$agnitude(lhs - rhs) < kEpsilon * kEpsilon;
while Equals looks like this, so there's a difference between the two
return x.Equals(other.x) && y.Equals(other.y) && z.Equals(other.z);
Your answer
Follow this Question
Related Questions
Vector3 using Doubles Instead of Floats 2 Answers
Convert double to float for Vector3 1 Answer
More precise Vector3 2 Answers
More Vector3 decimal precision in the Console? 3 Answers
My camera shake script works in editor and web, but not iPhone 0 Answers