Why is my angle of 2 vectors function return NaN even though i follow the formula

Viewed 334

I'm making a function that calculates the angle between 2 given vectors for my unity game using the dot product formula:

vector(a)*vector(b)=|vector(a)|*|vector(b)|*cos(the angle)

so I figured that the angle would equals

acos((vector(a)*vector(b))/(|vector(a)|*|vector(b)|))

Anyway here's my code:

float rotateAngle(Vector2 a,Vector2 b)
    {
        return Mathf.Acos((a.x * b.x + a.y * b.y) / ((Mathf.Sqrt(a.x * a.x + a.y * a.y)) * (Mathf.Sqrt(b.x * b.x + b.y * b.y)))) * (180 / Mathf.PI);
    }

But when i played it the console showed NaN. I've tried and reviewed the code and the formula but returned empty-handed.

Can someone help me? Thank you in advanced!!

2 Answers

float.NaN is the result of undefined (for real numbers) mathematical operations such as 0 / 0 (note from the docs that x / 0 where x != 0 rather returns positive or negative infinity) or the square root of a negative value. As soon as one operant in an operation already is NaN then also the entire operation returns again NaN.

The second (square root of a negative value) can not happen here since you are using squared values so most probably your vectors have a magnitude of 0.


If you look at the Vector2 source code you will find their implementation of Vector2.Angle or Vector2.SignedAngle (which you should rather use btw as they are tested and way more efficient).

    public static float Angle(Vector2 from, Vector2 to)
    {
        // sqrt(a) * sqrt(b) = sqrt(a * b) -- valid for real numbers
        float denominator = (float)Math.Sqrt(from.sqrMagnitude * to.sqrMagnitude);
        if (denominator < kEpsilonNormalSqrt)
            return 0F;

        float dot = Mathf.Clamp(Dot(from, to) / denominator, -1F, 1F);
        return (float)Math.Acos(dot) * Mathf.Rad2Deg;
    }

    // Returns the signed angle in degrees between /from/ and /to/. Always returns the smallest possible angle
    public static float SignedAngle(Vector2 from, Vector2 to)
    {
        float unsigned_angle = Angle(from, to);
        float sign = Mathf.Sign(from.x * to.y - from.y * to.x);
        return unsigned_angle * sign;
    }

There you will find that the first thing they check is

float denominator = (float)Math.Sqrt(from.sqrMagnitude * to.sqrMagnitude);
if (denominator < kEpsilonNormalSqrt)
    return 0F;

which basically makes exactly sure that both given vectors have a "big enough" magnitude, in particular one that is not 0 ;)


Long story short: Don't reinvent the wheel and rather use already built-in Vector2.Angle or Vector2.SignedAngle

NaN are typically the result of invalid mathematical operations on floating point numbers. A common source is division by zero, so my guess would be that the vector is 0,0.

I would also recommend using the built in functions for computing the normalization, Length/Magnitude, Dot etc. that will make the code much easier to read, and the compiler should be fairly good at optimizing that kind of code. If you need to do any additional optimization, only do so after you have done some measurements.

Related