I am trying to calculate the angle between two vectors.

Here is my relevant code:

cout << "\n\nPoint1 "; Point1.dump();
cout << "Point2 "; Point2.dump();

cout << "\nanswer: " << Point1.dot(Point2) << endl;
cout << "\nacos: " << acos(-1)<< endl;
cout << "Problem: " << acos(Point1.dot(Point2)) << endl;
cout << "acos1 "<< acos(1) <<endl;
double a=Point1.dot(Point2); cout << "a " << acos(a) << endl;

Point1 and Point2 are both unit vectors (using a vector class of my own design). The class function Point1.dot(Point2) calculates the dot product between Point1 and Point2 and I have verified that this works correctly. The dot product of two unit vectors should be the cos of the angle between them. So, acos() should give me the angle. But, it does not.

Here is the output:

Point1: 0.818436, -0.477041, 0.320304
Point2: -0.818436, 0.477041, -0.320304

answer: -1

acos: 3.14150
Problem: nan
acos1: 0
a nan

The dump class function writes the vector.

You can see that the vectors are identical except that the signs of their elements are switched. So, the reported dot product between them is correctly reported as -1.

When I ask for acos(-1) I get the correct result of 3.14159 (PI) radians.

But, when I do acos(Point1.dot(Point2)) I get nan -- not a number -- as the result.

When I try double a=Point1.dot(Point2) and then ask for acos(a) I also get nan.

So, why do I get the correct answer of -1 as the dot product between my two vectors, but get nan when I ask for the acos of that result?

Why does acos() work sometimes, but not all the time?

I suspect that this is something very simple and I am just not seeing it. What am I missing?

Using MinGW.

Check you code with this ...

// dotProduct.cpp //  // 2015-07-23 //

// find dot product and angle between ... two (2D) vectors (Points) //

#include <iostream>
#include <string>
#include <cmath> // re. ceil

// ok to do this, for now
using namespace std;

const string INTRO =
    "This program asks for input in a loop ... \n";

const double DEG_PER_RAD = 180.0 / acos(-1);


double takeInDbl( const std::string& msg,
                  const std::string& errMsg = "Error! Try again ...\n" ) ;


class Point
{
public:
    // ctor...
    Point( double x=0, double y=0 ) : x(x), y(y) {}

    void takeIn()
    {
        while( true )
        {
            x = takeInDbl( "Enter x: " );
            y = takeInDbl( "Enter y: " );
            if( x == 0 && y == 0 )
            {
                cout << "Point(0, 0) is NOT a valid entry here ...\n";
            }
            else break;
        }
    }

    double length() const
    {
        return sqrt( x*x + y*y );
    }

    double operator * ( const Point& pb ) const
    {
        return ( x*pb.x + y*pb.y );
    }

    Point operator / ( const double& dbl ) const
    {
        return Point( x/dbl, y/dbl );
    }

    Point unit() const
    {
        return *this / length();
    }

private:
    double x, y;

    friend ostream& operator << ( ostream& os, const Point& pt )
    {
        return os << "(" << pt.x << ", " << pt.y << ")" ;
    }
} ;


bool more( const string& msg = "More (y/n) ? " );



int main() ////////////////// BEGIN MAIN ///////////////////
{
    cout << INTRO << endl;
    do
    {
        Point p1, p2, p1u, p2u;

        cout << "For point 1 ... \n";
        p1.takeIn();

        cout << "For point 2 ... \n";
        p2.takeIn();

        p1u = p1.unit();
        p2u = p2.unit();

        double dotPrd = p1u*p2u;

        // fix up possible 'float' rounding error //
        if( dotPrd < -1.0 ) dotPrd = -1.0;

        cout << p1u << " * " << p2u << " = " << dotPrd << '\n';
        cout << "Angle in degrees is: " << acos( dotPrd ) * DEG_PER_RAD << '\n';
    }
    while( more() );

} ////////////////////////// END MAIN //////////////////////



bool more( const string& msg )
{
    cout << msg << flush;
    string line;
    getline( cin, line );
    if( line.size() && tolower(line[0]) ==  'n' ) return false;
    // else // defaults to yes, more
    return true;
}


double takeInDbl( const std::string& msg, const std::string& errMsg )
{
    double val = 0.0;
    while( true )
    {
        std::cout << msg << std::flush;
        if( std::cin >> val && std::cin.get() == '\n' )
            break;
        else
        {
            std::cout << errMsg;
            std::cin.clear(); // clear error flasgs
            std::cin.sync(); // 'flush' cin stream ...
        }
    }
    return val;
}

Edited 1 Year Ago by David W

The chances are that your error is actually the accuracy of the return value from the dot product.

With floating point calculations you often get a little bit of an error, so you might be returing -1.0000000001 from your vector dot product. The quickest way to check that is to simply do

 std::cout<<"Should be zero: "<<Point1.dot(Point2)+1.0<<std::endl;

If you see a very very small negative number then that is why acos will return NaN. There are ways round this either simple tests (e.g. checing the number is >1.0 or <-1.0) or by using mathermatical identies that force the number into range regardless of the floating point roundoff error.

[Note: in this case I think that if A and B are unit vectors +/- roundoff error then (A.dot(B)/(A.dot(A)*B.dot(B)) is bound within +/-1.0 -- but I am not 100% and you should check this before you rely on it -- I just wanted to show the kind of things I was talking about]

Sorry for being late in marking this question as solved.

The second responder pointed out the potential floating point rounding error in lines 94-95 of the suggested sample code.

That rounding error of floating point values was the "something simple" that I suspected, but could not see. Sometimes these simple things are the hardest coding problems to solve.

The problem makes sense now.

Thanks for helping.

If there is problem wiht nan, yo go to chuch...
Well it is something you get as answer to ...
so you check if that is nun and then do what you need to do

This question has already been answered. Start a new discussion instead.