C++ Sin 和 Cos 给出了已知角度的意外结果
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/31502120/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Sin and Cos give unexpected results for well-known angles
提问by Paul Morriss
I am sure this is a really stupid question, but when I pass an angle of 180 degrees into c/c++'s cos() and sin() functions I appear to receive an incorrect value. I know that it should be: sin of 0.0547 and cos of 0.99 but I get sin of 3.5897934739308216e-009 and cos of -1.00000
我确信这是一个非常愚蠢的问题,但是当我将 180 度角传递给 c/c++ 的 cos() 和 sin() 函数时,我似乎收到了不正确的值。我知道它应该是:0.0547 的 sin 和 0.99 的 cos 但我得到 3.5897934739308216e-009 的 sin 和 -1.00000 的 cos
My code is:
我的代码是:
double radians = DegreesToRadians( angle );
double cosValue = cos( radians );
double sinValue = sin( radians );
DegreesToRadians() is:
DegreesToRadians() 是:
double DegreesToRadians( double degrees )
{
return degrees * PI / 180;
}
Thank you :)
谢谢 :)
回答by chux - Reinstate Monica
C/C++ provides sin(a)
, cos(a)
, tan(a)
, etc. functions that require a parameter with radianunits rather than degrees. double DegreesToRadians(d)
performs a conversion that is closebut an approximate as the conversion results are rounded. Also machine M_PI
is close, but not the same value as the the mathematical irrational π
.
C/C++ 提供sin(a)
、cos(a)
、tan(a)
等函数,这些函数需要带弧度单位而不是度数的参数。 double DegreesToRadians(d)
执行接近但近似的转换,因为转换结果四舍五入。机器也M_PI
很接近,但与数学无理数的值不同π
。
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
.
由于四舍五入、有限精度和可能的弱值,OP 的代码180
通过 to DegreesToRadians(d)
和 tosin()/cos()
给出了与预期不同的结果。double()
PI
An improvement is to perform argument reduction in degreesbefore 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.
一个改进是在调用 trig 函数之前以度数执行参数减少。下面首先将角度减小到 -45° 到 45° 范围,然后调用sin()
. 这将确保N
in 的大值sind(90.0*N) --> -1.0, 0.0, 1.0
。. 注意:sind(360.0*N +/- 30.0)
可能不完全相等+/-0.5
。需要一些额外的考虑。
#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
...
回答by ForceBru
First of all, a cosine of 180 degrees should be equal to -1
, so the result you got is right.
首先,180度的余弦应该等于-1
,所以你得到的结果是正确的。
Secondly, you sometimes can't get exactvalues when using sin/cos/tan
etc functions as you always get results that are the closest to the correct ones. In your case, the value you got from sin
is the closest to zero.
其次,在使用etc 函数时有时无法获得精确值,sin/cos/tan
因为您总是得到最接近正确结果的结果。在您的情况下,您从中获得的值sin
最接近于零。
The value of sin(PI)
that you got differs from zero only in the 9th(!) digit after the floating point. 3.5897934739308216e-009
is almost equal to 0.000000004
and that's almost equal to zero.
的价值sin(PI)
,你只有在得到了不同于零9日浮点后(!)的数字。3.5897934739308216e-009
几乎等于0.000000004
并且几乎等于零。
回答by Keith Knauber
I have the same problem as the OP when converting app to 64-bit.
My solution is to use the new math.h functions __cospi() and __sinpi().
Performance is similar (even 1% faster) than cos() and sin().
将应用程序转换为 64 位时,我遇到了与 OP 相同的问题。
我的解决方案是使用新的 math.h 函数 __cospi() 和 __sinpi()。
性能与 cos() 和 sin() 相似(甚至快 1%)。
// cos(M_PI * -90.0 / 180.0) returns 0.00000000000000006123233995736766
//__cospi( -90.0 / 180.0) returns 0.0, as it should
// #define degree2rad 3.14159265359/180
// #define degree2rad M_PI/ 180.0
// double rot = -degree2rad * ang;
// double sn = sin(rot);
// double cs = cos(rot);
double rot = -ang / 180.0;
double sn = __sinpi(rot);
double cs = __cospi(rot);
From math.h:
来自 math.h:
/* __sinpi(x) returns the sine of pi times x; __cospi(x) and __tanpi(x) return
the cosine and tangent, respectively. These functions can produce a more
accurate answer than expressions of the form sin(M_PI * x) because they
avoid any loss of precision that results from rounding the result of the
multiplication M_PI * x. They may also be significantly more efficient in
some cases because the argument reduction for these functions is easier
to compute. Consult the man pages for edge case details. */