C++ 对于已知角度,Sin和Cos会给出意外的结果

C++ 对于已知角度,Sin和Cos会给出意外的结果,c++,floating-point,trigonometry,cmath,C++,Floating Point,Trigonometry,Cmath,我确信这是一个非常愚蠢的问题,但当我将180度的角度传递到c/c++的cos()和sin()函数时,我似乎收到了一个错误的值。我知道应该是: sin为0.0547,cos为0.99 但我得到的sin为3.5897934739308216e-009,cos为-1.00000 我的代码是: double radians = DegreesToRadians( angle ); double cosValue = cos( radians ); double sinValue = sin( radia

我确信这是一个非常愚蠢的问题,但当我将180度的角度传递到c/c++的cos()和sin()函数时,我似乎收到了一个错误的值。我知道应该是: sin为0.0547,cos为0.99 但我得到的sin为3.5897934739308216e-009,cos为-1.00000

我的代码是:

double radians = DegreesToRadians( angle );
double cosValue = cos( radians );
double sinValue = sin( radians );
DegreesToRadians()是:


谢谢:)

首先,180度的余弦应该等于
-1
,因此您得到的结果是正确的

其次,当使用
sin/cos/tan
etc函数时,有时无法获得准确的值,因为您总是得到最接近正确值的结果。在您的例子中,从
sin
获得的值最接近于零

您得到的
sin(PI)
值仅在浮点后的第9位(!)与零不同
3.5897934739308216e-009
几乎等于
0.00000000 4
,这几乎等于零。

C/C++提供了
sin(a)
cos(a)
tan(a)
等需要以弧度为单位的参数的函数<代码>双度弧度(d)执行近似的转换,转换结果四舍五入。机器
M_PI
也很接近,但与数学无理
π
的值不同

将带有
180
的OP代码传递到
degreestorarians(d)
然后传递到
sin()/cos()
会给出不同于预期的结果,这是因为四舍五入、
double()
的有限精度以及
PI的可能较弱的值

一个改进是在调用trig函数之前执行参数缩减(以度为单位)。下面的命令首先将角度减小到-45°到45°范围,然后调用
sin()
。这将确保
sind(90.0*N)-->-1.0、0.0、1.0
中的
N
的大值。注:
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;
}

将应用程序转换为64位时,我遇到与OP相同的问题。
我的解决方案是使用新的math.h函数_cospi()和_sinpi()。
性能与cos()和sin()相似(甚至快1%)

来自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.                 */

我知道它应该是:sin为0.0547,cos为0.99
更像是“0和-1”。PI的正弦为0,余弦为-1。这听起来像是你得到的“罪为0.0547,因为0.99”啊?它应该正好是0和-1。您的代码正确地导出了(最大舍入误差)。sin(π度)和cos(π度)分别为0.0548和0.998。sin(π弧度)和cos(π弧度)分别为0和-1。这是一个很好的问题。为什么会有人否决这个?标准库中有一个bug,通过添加新的_sinpi()和_cospi()函数“修复”了该bug。谢谢,很抱歉,在转换时,我弄错了方向:(@chux我假设“给出的结果与预期不同”的意思是“给出的结果与预期不同”?@njuffa好主意,可以这样说,不清楚OP想要多近。这个答案表明,通过先对度进行范围缩小,然后转换为弧度,我们甚至可以做得更好,并以180度返回预期的精确值。尽管使用
\uu sinpi(),\uu cospi()
使用弧度参数减少误差是个好主意,
ang/180.0
本身为许多值注入舍入误差。因此,当
ang/180.0
的商是精确的时,减少误差是个好主意,否则就不是这样了。
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
...
//    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);
/*  __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.                 */