Why Do Sin(45) and Cos(45) Give Different Results

Why do Python's trigonometry functions give different results than my calculator?

Take a look at the documentation for the math.tan function in Python:

math.tan(x)

Return the tangent of x radians

This applies to all the trigonometric functions. You must convert degrees to radians first, with the math.radians function:

math.tan(math.radians(ang))

Sin and Cos give unexpected results for well-known angles

C/C++ provides sin(a), cos(a), tan(a), etc. functions that require a parameter with radian units rather than degrees. double DegreesToRadians(d) performs a conversion that is close but an approximate as the conversion results are rounded. Also machine M_PI is close, but not the same value as the the mathematical irrational π.

OP's code with 180 passed to DegreesToRadians(d) and then to sin()/cos() gives results that differ than expected due to rounding, finite precision of double() and possible a weak value for PI.

An improvement is to perform argument reduction in degrees before calling the trig function. The below reduces the angle first to a -45° to 45° range and then calls sin(). This will insure that large values of N in sind(90.0*N) --> -1.0, 0.0, 1.0. . Note: sind(360.0*N +/- 30.0) may not exactly equal +/-0.5. Some additional considerations needed.

#include <math.h>
#include <stdio.h>

static double d2r(double d) {
return (d / 180.0) * ((double) M_PI);
}

double sind(double x) {
if (!isfinite(x)) {
return sin(x);
}
if (x < 0.0) {
return -sind(-x);
}
int quo;
double x90 = remquo(fabs(x), 90.0, &quo);
switch (quo % 4) {
case 0:
// Use * 1.0 to avoid -0.0
return sin(d2r(x90)* 1.0);
case 1:
return cos(d2r(x90));
case 2:
return sin(d2r(-x90) * 1.0);
case 3:
return -cos(d2r(x90));
}
return 0.0;
}

int main(void) {
int i;
for (i = -360; i <= 360; i += 15) {
printf("sin() of %.1f degrees is % .*e\n", 1.0 * i, DBL_DECIMAL_DIG - 1,
sin(d2r(i)));
printf("sind() of %.1f degrees is % .*e\n", 1.0 * i, DBL_DECIMAL_DIG - 1,
sind(i));
}
return 0;
}

Output

sin()  of -360.0 degrees is   2.4492935982947064e-16
sind() of -360.0 degrees is -0.0000000000000000e+00 // Exact

sin() of -345.0 degrees is 2.5881904510252068e-01 // 76-68 = 8 away
// 2.5881904510252076e-01
sind() of -345.0 degrees is 2.5881904510252074e-01 // 76-74 = 2 away

sin() of -330.0 degrees is 5.0000000000000044e-01 // 44 away
// 0.5 5.0000000000000000e-01
sind() of -330.0 degrees is 4.9999999999999994e-01 // 6 away

sin() of -315.0 degrees is 7.0710678118654768e-01 // 68-52 = 16 away
// square root 0.5 --> 7.0710678118654752e-01
sind() of -315.0 degrees is 7.0710678118654746e-01 // 52-46 = 6 away

sin() of -300.0 degrees is 8.6602540378443860e-01
sind() of -300.0 degrees is 8.6602540378443871e-01
sin() of -285.0 degrees is 9.6592582628906842e-01
sind() of -285.0 degrees is 9.6592582628906831e-01
sin() of -270.0 degrees is 1.0000000000000000e+00 // Exact
sind() of -270.0 degrees is 1.0000000000000000e+00 // Exact
...

Math.sin incorrect results even when converted to degrees

You need to multiply the value in degree by (pi/180) to convert into the equivalent value in radians

var reactant = 45;var vi = 0;function click25() {    if (vi === 0) {        reactant = Math.sin(reactant * (Math.PI / 180))    }    console.log(reactant);}
click25();

Why do I get platform-specific result for std::exp?

The standard does not define how the exp function (or any other math library function1) should be implemented, thus each library implementation may use a different computing method.

For instance, the Android C library (bionic) uses an approximation of exp(r) by a special rational function on the interval [0,0.34658] and scales back the result.

Probably the Microsoft library is using a different computing method (cannot find info about it), thus resulting in different results.

Also the libraries could take a dynamic load strategy (i.e. load a .dll containing the actual implementation) in order to leverage the different hardware specific features, making it even more unpredictable the result, even when using the same compiler.

In order to get the same implementation in both (all) platforms, you could use your own implementation of the exp function, thus not relying on the different implementations of the different libraries.

Take into account that maybe the processors are taking different rounding approaches, which would yield also to a different result.

1 There are some exceptions to these, for isntance the sqrt function or std::fma and some rounding functions and basic arithmetic operations

Standard for the sine of very large numbers

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.

Most good math libraries strive to deliver faithfully rounded results over the entire range (yes, even for huge inputs to sin( ) and similarly hard cases). As you note, this requires that the library know somewhat more digits of π then there are digits in the largest representable number. This is called an "infinite-pi" argument reduction.

To the point that @spraff raises, good math libraries adopt the viewpoint that the inputs are infinitely precise (i.e., the function should behave as though the input is always represented accurately). One can debate whether or not this is a reasonable position, but thats the working assumption for essentially all good math libraries.

All that said, there are plenty of libraries that take the easy route and use a "finite-pi" reduction, which basically treats a function like sin( ) as though π were a representable finite number. It turns out that this doesn't really cause any trouble for most uses, and is certainly easier to implement.

why is this sin method returning a wrong answer?

You are computing the sin of 100.7 radians, and the answer given is the correct one.



Related Topics



Leave a reply



Submit