The basic problem you're having is one of limited precision of float
and the value of pi
that you're using. Moving to a double
will help, and since you're already including <cmath>
you should use the value there which is M_PI
and is accurate to at least the precision of double
. With that said, you're still not going to get exact answers with this approach. (The answer from alain does a good job of explaining why.)
There are some improvements that could be made. One is a neat trick using a C++11 feature which is "user-defined string literals." If you add this definition to your code:
constexpr long double operator"" _deg(long double deg) {
return deg*M_PI/180;
}
You can now append _deg
to any long double literal and it will automatically be converted to radians at compile time. Your main
function would then look like this:
int main(){
Vec v1(0.0_deg, 3);
Vec v2(90.0_deg, 3);
Vec v3(180.0_deg, 3);
// ...
}
The next thing you could do would be to store the x and y coordinates and only do the trigonometric manipulations when needed. That version of Vec
might look like this:
class Vec{
double x,y;
public:
Vec(double dir, double mag, bool cartesian=false) : x(dir), y(mag) {
if (!cartesian) {
x = mag*cos(dir);
y = mag*sin(dir);
}
}
double getX() const {
return x;
}
Vec operator + (const Vec &v2){
return Vec(x+v2.x, y+v2.y, true);
}
}
Note that I've created a bool
value for the constructor which tells whether the input is to be a magnitude and direction or an x and y value. Also note that the getX()
is declared const
because it doesn't alter the Vec
and that the argument to operator+
is also a const
reference for the same reason. When I make those changes on my machine (a 64-bit machine), I get the following output:
v1: 3
v1+v2: 3
v1+v3: 0