Cos is not returning 0 for 90 degrees or PI/2

Started by
32 comments, last by ApochPiQ 11 years, 10 months ago

Vector2 Rotate( Vector2 &vec,float Angle )
{
/*
cos -sin
sin cos
*/

// When the Angle is PI/2 (90 degrees), it doesn't return 0, we get 4.37114e-008
float Cos = cos(Angle);
float Sin = sin(Angle);

Vector2 rot = Vector2( Cos*vec.x - Sin*vec.y , Sin*vec.x + Cos*vec.y );

return rot;
}

// If i pass this vector
Vector2 vec = Vector2(0,1);
vec = Rotate(vec,PI*.5f);

// The answer should be '(1,0)'
// But i ACTUALLY get '(-1,-4.37114e-008)'....

/* Anyone know what's going on here, is sin and cos incapable of returning 0? */

Advertisement
I get the same behaviour, where the answer is -4.37114e-008 for float and 6.12323e-017 for double. Consider that [eqn]\pi[/eqn] is irrational, and so you shouldn't really expect a perfect answer. When you use a digital computer / calculator and plug in [eqn]\cos(\pi / 2)[/eqn] and get an answer of precisely zero, it's likely because the person who coded the calculator put in a special conditional statement that says something similar to "if(answer < epsilon && answer > -epsilon) { answer = 0; }", where epsilon is some tiny number like 1e-7.

Don't lose sleep over it.

// The answer should be '(1,0)'
// But i ACTUALLY get '(-1,-4.37114e-008)'....



Well, the answer should be (-1,0), which it basically is... You can't expect infinite precision in floating-point operations.

EDIT: If instead of an angle you were to use a unit vector containing the angle's cosine and sine, you could just do this and not have the problem:
Vector2D rotate(Vector2D vec, Vector2D rot) {
return Vector2D(vec.x*rot.x - vec.y*rot.y, vec.x*rot.y + vec.y*rot.x); // Notice this is just multiplication of complex numbers!
}

Vector2 vec = Vector2(0,1);
vec = Rotate(vec,Vector2D(0,1));
Not that it has anything to do with your question, but `vec' should not be a non-const reference: Either make it const or remove the `&'.
What Every Computer Scientist Should Know About Floating-Point Arithmetic

-4.37114e-008 = -.0000000437114 (which is pretty dang close to zero)
[size=2][ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]

What Every Computer Scientist Should Know About Floating-Point Arithmetic

-4.37114e-008 = -.0000000437114 (which is pretty dang close to zero)


oh, i assumed it was a garbage number that it spit out cause it didn't know what to do lol

thanks guys



[quote name='Muzzy A' timestamp='1337404899' post='4941354']
// The answer should be '(1,0)'
// But i ACTUALLY get '(-1,-4.37114e-008)'....



Well, the answer should be (-1,0)

[/quote]

lol oops

it's likely because the person who coded the calculator put in a special conditional statement that says something similar to "if(answer < epsilon && answer > -epsilon) { answer = 0; }", where epsilon is some tiny number like 1e-7.

It turns out the language has a constant for the actual epsilon that should be used for that. Proper use of FLT_EPSILON would apply here.

( In this case, the answer is ten times smaller than FLT_EPSILON, so ten times smaller than rounding error. )
Calculators generally work to a much higher precision than what they display. For example the Windows calculator (at least on recent versions of windows) has about 40 significant digits of precision (calculate sqrt(4) - 2 to see that). They then round the answer to fit the number of digits on the display.

Note that FLT_EPSILON is simply the minimum positive float such that 1.0f + FLT_EPSILON != 1.0f so the epsilon value you want to use depends on the magnitude of the expected answer. In the case of sin and cos it's probably the right epsilon to use, but in other cases it won't be.

-4.37114e-008 = -.0000000437114 (which is pretty dang close to zero)


Not if you're calculating the mass defect of an atom nucleus decaying by beta-radiation cool.png
which I currently have to do for class... 4,014e-31 kg...

Not if you're calculating the mass defect of an atom nucleus decaying by beta-radiation cool.png

In which case choosing stock float as the data type to use is quite obviously a baaaaaaaaaaaaaaaaaad idea.

Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls.

This topic is closed to new replies.

Advertisement