Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Comparing two identical Vector3 returns false

Discussion in 'Scripting' started by nicola secco, May 20, 2015.

  1. nicola secco

    nicola secco

    Joined:
    Mar 7, 2013
    Posts:
    3
    Hi everyone,

    I am writing a C# script on Unity 3D. I have two Vector3 that are the same. When I do:

    Debug.Log(vect1);
    Debug.Log(vect2);

    I get the same result (500.0, 150.0, 0.0).

    The problem is that when I do:

    vect1.Equals(vect2)

    I get false! The same happens if I use the == operator

    vect1==vect2

    P.S. I am sure that they are both Vector3 because when I do vect1.GetType() and vect2.GetType() I always get Vector3.
     
  2. Iron-Warrior

    Iron-Warrior

    Joined:
    Nov 3, 2009
    Posts:
    838
    Try debugging out the Vector using the ToString method with the F8 parameter, like so:

    Code (csharp):
    1. Debug.Log(vect1.ToString("F8"));
    This will print the string with 8 points of precision, allowing you to see exactly what the vector is. According to the documentation page though, the == operator should return true even if they're fairly close.
     
    Ex6tra, Abdulrazek and Soaphog like this.
  3. Nitugard

    Nitugard

    Joined:
    May 10, 2015
    Posts:
    343
    Try to check distance between two vectors. Very close distance means that they are almost equal!
     
    hopetolive and Joe-Censored like this.
  4. Darkcoder

    Darkcoder

    Joined:
    Apr 13, 2011
    Posts:
    3,406
    The Vector's default ToString method has a very low precision, so it's easy to not see the difference. Also, the Vector's == operator doesn't just do == on each float, instead it checks if the magnitures are within some fixed threshold value, which can easily happen on very large vectors where the precision is low. So in general you shouldn't use == with vectors unless you know what you're doing. In most cases you should use Vector3.Distance or similar to check if it's close enough to your target.
     
    Thalon4, c8theino and Joe-Censored like this.
  5. VipHaLongPro

    VipHaLongPro

    Joined:
    Mar 8, 2015
    Posts:
    49
    I've experienced this but it returned false only for Equals method. Using == operator should return true.
     
  6. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,773
    As a general rule, if you're using == between two Vector3's, you shouldn't be. The same applies to floats (or, more accurately, it applies to Vector3 because it applies to floats). Floating point numbers are notoriously *slightly* inaccurate. The inaccuracies usually don't matter, UNLESS you're using the == operator, because 1.0000001 is not 1, and sometimes when using floats, 1f / 2f * 2f can equal 1.00000001.

    Anytime you need to do that sort of check, check against distance as @OneDragutin suggested.

    (If CPU efficiency is key in that situation, you should use (vector1 - vector2).sqrMagnitude - it will give you the square of the distance (which is fine for this comparison), which will be faster than .Distance because .Distance has to compute a square root, which is really slow.)
     
  7. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,514
    This came up a couple weeks ago in another thread, and we determined why == and Equals acts differently. Unity actually coded them differently (UGH!). From the UnityEngine dll for Vector3:

    Code (csharp):
    1.  
    2.     public override bool Equals(object other)
    3.     {
    4.       if (!(other is Vector3))
    5.         return false;
    6.       Vector3 vector3 = (Vector3) other;
    7.       if (this.x.Equals(vector3.x) && this.y.Equals(vector3.y))
    8.         return this.z.Equals(vector3.z);
    9.       else
    10.         return false;
    11.     }
    12.  
    13.     public static bool operator ==(Vector3 lhs, Vector3 rhs)
    14.     {
    15.       return (double) Vector3.SqrMagnitude(lhs - rhs) < 0.0 / 1.0;
    16.     }
    17.  
    == actually does the SqrMagnitude like everyone is suggesting. But .Equals compares the vectors directly.

    Personally, I never use either of these methods, so I never tripped over it myself. Floats are inherently inaccurate, so I've never designed anything to need to know if 2 vectors are equal. In my opinion in game design, it's a weird thing to test for. I might test if 2 vectors are NEAR one another, but never equal.

    Except for zero vector, I do see the need to test that. Which is why I have these 2 methods in my VectorUtil:
    Code (csharp):
    1.  
    2. public static bool NearZeroVector(this Vector3 v)
    3. {
    4. return MathUtil.FuzzyEqual(v.sqrMagnitude, 0f, MathUtil.EPSILON_SQR);
    5. }
    6. public static bool NearZeroVector(this Vector2 v)
    7. {
    8. return MathUtil.FuzzyEqual(v.sqrMagnitude, 0f, MathUtil.EPSILON_SQR);
    9. }
    10.  
    https://github.com/lordofduct/space...lob/master/SpacepuppyBase/Utils/VectorUtil.cs


    NOTE - I totally suggest explicitly testing the 'nearness' with sqrMagnitude as suggested by everyone and just straight up ignore the == and .Equals methods. The fact they don't act the same, is bad design. Furthermore they don't act like what the operator implies... == does not imply to me fuzzy equality, it implies equality. I'd write a 'FuzzyEquals' method, like in my VectorUtil class again:

    Code (csharp):
    1.  
    2.  
    3.         public static bool FuzzyEquals(this Vector2 a, Vector2 b)
    4.         {
    5.             return MathUtil.FuzzyEqual(Vector3.SqrMagnitude(a - b), MathUtil.EPSILON_SQR);
    6.         }
    7.  
    8.         public static bool FuzzyEquals(this Vector2 a, Vector2 b, float epsilon)
    9.         {
    10.             return MathUtil.FuzzyEqual(Vector3.SqrMagnitude(a - b), epsilon);
    11.         }
    12.  
    13.         public static bool FuzzyEquals(this Vector3 a, Vector3 b)
    14.         {
    15.             return MathUtil.FuzzyEqual(Vector3.SqrMagnitude(a - b), MathUtil.EPSILON_SQR);
    16.         }
    17.  
    18.         public static bool FuzzyEquals(this Vector3 a, Vector3 b, float epsilon)
    19.         {
    20.             return MathUtil.FuzzyEqual(Vector3.SqrMagnitude(a - b), epsilon);
    21.         }
    22.  
    23.  
    https://github.com/lordofduct/space...lob/master/SpacepuppyBase/Utils/VectorUtil.cs

    This way, when you write the code, it reads explicitly like what it's doing. You know this isn't testing equality... it's testing fuzzy equality.
     
    Last edited: May 20, 2015
  8. nicola secco

    nicola secco

    Joined:
    Mar 7, 2013
    Posts:
    3
    Hi guys,

    I solved the problem by doing a member to member comparison instead of a vector to vector comparison.

    int x1=(int)vect1.x;
    int y1=(int)vect1.y;
    int z1=(int)vect1.z;
    int x2=(int)vect2.x;
    int y2=(int)vect2.y;
    int z2=(int)vect2.z;
    Debug.Log((x1==x2)&&(y1==y2)&&(z1==z2));

    In this way it's a simple comparison between integers, so it works.
     
  9. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,514
    you're converting the values to int. That's a fairly large rounding range. Vectors with as much distance as nearly 2 units in distance from one another will equate as equal.

    <0.99f, 0.99f, 0.99f> and <-0.99f, -0.99f, -0.99f> (note those are positive and negative) would be equal.

    Also, it's notably more code than the fuzzyequals options I showed you. Which allows for more control over the rounding size (epsilon). With it you get to decide how close the vectors need to be to be considered equal.
     
    hopetolive likes this.
  10. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,773
    I think the main problem with this is that it will tell you that 2.99999999 and 3 are not equal, which is something that can easily happen with floating point math.
     
  11. arutyunef

    arutyunef

    Joined:
    May 30, 2019
    Posts:
    3
    1. public override bool Equals(object other)
    2. {
    3. if (!(other is Vector3))
    4. return false;
    5. Vector3 vector3 = (Vector3) other;
    6. if (this.x.Equals(vector3.x) && this.y.Equals(vector3.y))
    7. return this.z.Equals(vector3.z);
    8. else
    9. return false;
    10. }
    Why is this code written so silly? What's the point? All of this can be written in a much shorter way, in a single line:

    1. public override bool Equals(object other) => other is Vector3 vector3 && x.Equals(vector3.x) && y.Equals(vector3.y) && z.Equals(vector3.z)
     
  12. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,294
    Don't necro 4 year threads to complain about unimportant stuff. That method was generated by a decompiler, so it's going to look ugly. You can find the actual source here, as it's public these days.
    Also use code tags.
     
    npatch, Joe-Censored and lordofduct like this.
  13. Abdulrazek

    Abdulrazek

    Joined:
    Mar 4, 2018
    Posts:
    5
    You saved my life! tysm
     
  14. Anisoropos

    Anisoropos

    Joined:
    Jul 30, 2012
    Posts:
    102
    Since the necro has happened already, might as well share a clean-up / iteration I did on @lordofduct 's code above.

    Using expression bodies for methods and written in a slightly different way, plus a way to avoid situations where a Vector3 is practically zero but not for the purposes of Quaternion.LookRotation where it would result in a Look rotation viewing vector is zero error.

    If the error persists after validating with myVector3.IsValidViewingVector(), shave a few "0"s off of EPSILON_VIEWING_VECTOR

    Code (CSharp):
    1.          
    2. private const double EPSILON = float.Epsilon;
    3. private const double EPSILON_SQR = EPSILON * EPSILON;
    4. private const double EPSILON_VIEWING_VECTOR = 0.000000000000001f;
    5. public static bool FuzzyEquals0(this float v, double epsilon = EPSILON) => FuzzyEquals(v, 0, epsilon);
    6. public static bool FuzzyEquals(this float v, float b, double epsilon = EPSILON) => (v - b).Abs() < epsilon;
    7. public static bool FuzzyEquals(this Vector2 a, Vector2 b, double epsilon = EPSILON_SQR) => FuzzyEquals0(Vector2.SqrMagnitude(a - b), epsilon);
    8. public static bool FuzzyEquals0(this Vector2 a, double epsilon = EPSILON_SQR) => FuzzyEquals0(Vector2.SqrMagnitude(a), epsilon);
    9. public static bool FuzzyEquals(this Vector3 a, Vector3 b, double epsilon = EPSILON_SQR) => FuzzyEquals0(Vector3.SqrMagnitude(a - b), epsilon);
    10. public static bool FuzzyEquals0(this Vector3 a, double epsilon = EPSILON_SQR) => FuzzyEquals0(Vector3.SqrMagnitude(a), epsilon);
    11. /// <summary>
    12. /// Use to filter out Vector3's that wouldn't cause an issue when used with <see cref="Quaternion.LookRotation(Vector3)"/>
    13. /// </summary>
    14. public static bool IsValidViewingVector(this Vector3 a) => !FuzzyEquals0(Vector3.SqrMagnitude(a), EPSILON_VIEWING_VECTOR);
    15.  
     
    Last edited: Apr 7, 2021
    MaciekXB likes this.