Why do sin(45) and cos(45) give different results?

2020-02-13 03:30发布

This is something I wasn't expecting. I know these numbers are not 100% exact, but I wasn't expecting complementary angles giving different results of sin and cos:

This following function returns 0.70710678118654746000000...

sin(45 * PI / 180.0);

while this follwing function returns 0.70710678118654757000000...

cos(45 * PI / 180.0);

so, it's:

0.707106781186547**46**000000... vs
0.707106781186547**57**000000...

and not only those... sin(1 * PI / 180.0) also returns a slightly different number than cos(89 * PI / 180.0) although they should be the same.

Moreover It's not only a sin vs cos problem, it's also a sin vs sin problem: sin(1 * PI / 180.0) returns a different value than sin(179 * PI / 180.0), again they should be the same.

I tried to use radians and not degrees, and there is exactly the same difference, I tried to use a small PI value, a huge PI value (around 100 decimals and more) and they're still different, I tried to use cmath instead of math.h, I tried to use M_PI instead of a PI defined by myself.

The difference is always the same, around the 16th decimal. Don't get me wrong, I know I will never get a 100% precise value of these numbers, but AT LEAST I was expecting to get the same "imprecise" value of sin and cos of complementary angles. What the hell is wrong with all this?


I need them to be the same because the program I'm working on (a gravity simulator I was asked to do) uses objects that have double (I also tried float) variables which are basically angles (degrees or radians, I've tried both). Those are the directions the objects use to move, also I need the angles to calculate the interactions between the objects.

The angles change in every iteration of the program, and in every iteration, the angles change basing on the calculations on the previous iteration's angles, so if there is any minimally wrong angle value at any point, that error gets amplified more and more in every iteration.

The program runs thousands and even millions of iterations, so the value's error gets absurdly huge! To put it clear, planets eventually get out of their balance and everything becomes a disaster, I'm really mad :(

P.s. I'm on Windows 7, 32 bits.

2条回答
你好瞎i
2楼-- · 2020-02-13 03:38

I know I will never get a 100% precise value of these numbers, but AT LEAST I was expecting to get the same "unprecise" value of sin and cos of complementary angles.

Why? The are calculated differently, so different floating point errors will occur (and accumulate). What you see is not an error; FP arithmetic isn´t predictable by math laws.

Btw., providing eg. 30 or 100 digits of PI won´t be anything different
if your type can´t hold 30 digits in the first place.

查看更多
狗以群分
3楼-- · 2020-02-13 04:01

regardless of how they are calculated, they are supposed to return the same value

Your expectations are incorrect. In IEEE-754 only basic operators (+-*/) and sqrt are required to be correctly rounded. Trancendental functions like sin, cos, exp... are not required because it's very complex

There is no standard that requires faithful rounding of transcendental functions. IEEE-754 (2008) recommends, but does not require, that these functions be correctly rounded.


Now if you look at your values

                                      ↓
0.70710678118654746 = 0x1.6a09e667f3bccp-1
0.70710678118654757 = 0x1.6a09e667f3bcdp-1
                                      ↑

So they are within 1ulp of each other and is precise enough in double precision

Don't get me wrong, I know I will never get a 100% precise value of these numbers, but AT LEAST I was expecting to get the same "unprecise" value of sin and cos of complementary angles

There's not only a single algorithm to calculate sin and cos. Each will be correct for some set of inputs but incorrect for some others. They also have different memory and time requirements so some can be very fast with higher error, some will require a lot more time and memory but they can achieve much higher accuracy.

Compiler implementations may use different algorithms for those functions so if you need consistent results, use a single carefully designed library across platforms. For example GCC uses MPFR for achieving correctly rounded results regardless of platforms

The GCC middle-end has been integrated with the MPFR library. This allows GCC to evaluate and replace at compile-time calls to built-in math functions having constant arguments with their mathematically equivalent results. In making use of MPFR, GCC can generate correct results regardless of the math library implementation or floating point precision of the host platform. This also allows GCC to generate identical results regardless of whether one compiles in native or cross-compile configurations to a particular target

https://gcc.gnu.org/gcc-4.3/changes.html#mpfropts

How does C compute sin() and other math functions?

查看更多
登录 后发表回答