不知道限制 sin(x) 公式循环

No idea for limit the sin(x) formula loop

使 c/++ 函数计算 sin(x)

通过公式引用;

但我不知道在哪里停止无穷和,我不想要快速回答的图书馆。我想成功。 我很好地制作了阶乘函数。 (事实()函数)

double sin(int x) {
    int tp=0;
    for(int k=1; ;k++)
    {
        tp+=pow(-1,k)*pow(x,2*k+1)/fact(2*k+1);
    }
    return tp;
}

你需要的是一个 epsilon 值,当我比我们要停止的那个数字更准确时你说的一个值。它看起来像 if(abs(prev_ans - cur_ans) < epsilon) break;

用数学术语来说,序列的 nn+1 部分总和变化很小,以至于继续序列不会产生任何更理想的精度

当计算出的值 (tp) 变化不大时,您应该停止。检查新计算值与旧值的差异,如果绝对差异(为此使用 fabs())小于 epsilon(您定义的),则停止迭代。

当你停下来的时候,你会得到一个近似的罪恶结果。

此外,int tp=0; 对我来说似乎不正确。当 k 为 0 时,你应该用公式结果初始化它。更重要的是,它应该是 double 类型,因为 int 是整数。

此外,值 x 不仅必须在 弧度 中,而且通常还必须在 -π 到 +π 范围内。

发布以供参考,这是我的版本,它使用级数扩展的各个组件的渐进式计算,而不是调用外部 O(n) 阶乘函数:

double mysin(double x)
{
    int sign = 1;
    int iteration = 1;
    double xn = x;
    double factorial = 1.0;
    double result = 0.0;
    double delta;

    while (iteration < 31) {
        delta = xn / factorial;
        result += sign * delta;
        xn *= x * x;
        sign = -sign;
        factorial *= ++iteration;
        factorial *= ++iteration;
    }
    return result;
}

根据我的测试,如果 fabs(delta) 变得太小,那么提早跳出似乎不会在准确性(或性能)方面有任何显着优势,除非 x 的初始值也是很小。

在我们继续之前,您必须对 return 类型和累加使用 double,否则结果将被(严重)截断。


当添加变化项不改变当前累加求和值时应停止,即存在下溢。这发生在:

The magnitude of the change term is less than the value of the lowest binary digit of the accumulator.

要检查这一点,提取浮点数的 指数 很有用。 This SO post 提供了一个有用的函数:frexp.

然后我们可以检查变化项的指数是否小于累加器的指数减去尾数[=50]中的位数=] double 类型(52 位)。如果您需要了解更多信息,请搜索 IEEE 浮点格式.


提高数值精度和速度的另一点:让我们检查连续项之间的关系:

因此,与其从头开始计算每一项(使用幂函数和阶乘函数),我们可以边计算边迭代计算每一项。


示例代码:

// best to use an existing C-library define for this, if exists
#define DBL_MANTISSA_BIT 52

double mysin_new(double x)
{
   double term = x;
   double sum = term;

   for (int n = 1; ; n++) {
      // next term in the series
      term *= - (x / (2*n)) * (x / (2*n+1));

      // check if the exponent is small enough for us to stop
      int e_term, e_sum;
      frexp(term, &e_term);
      frexp(sum, &e_sum);
      if (e_term <= e_sum - DBL_MANTISSA_BIT) break;

      sum += term;
   }

   return sum;
}

一些数值测试:

angle = 0.157080
  library  : 0.15643446504023086896f, 0011111111000100000001100000101101100111101010000101001101110101b
  mysin_old: 0.15643446504023086896f, 0011111111000100000001100000101101100111101010000101001101110101b
  mysin_new: 0.15643446504023089672f, 0011111111000100000001100000101101100111101010000101001101110110b

angle = 0.314159
  library  : 0.30901699437494739575f, 0011111111010011110001101110111100110111001011111110100101001111b
  mysin_old: 0.30901699437494745126f, 0011111111010011110001101110111100110111001011111110100101010000b
  mysin_new: 0.30901699437494739575f, 0011111111010011110001101110111100110111001011111110100101001111b

angle = 0.471239
  library  : 0.45399049973954674897f, 0011111111011101000011100010111000101011010001001101111000000000b
  mysin_old: 0.45399049973954674897f, 0011111111011101000011100010111000101011010001001101111000000000b
  mysin_new: 0.45399049973954674897f, 0011111111011101000011100010111000101011010001001101111000000000b

angle = 0.628319
  library  : 0.58778525229247313710f, 0011111111100010110011110010001100000100011101010101101001011110b
  mysin_old: 0.58778525229247313710f, 0011111111100010110011110010001100000100011101010101101001011110b
  mysin_new: 0.58778525229247313710f, 0011111111100010110011110010001100000100011101010101101001011110b

angle = 0.785398
  library  : 0.70710678118654746172f, 0011111111100110101000001001111001100110011111110011101111001100b
  mysin_old: 0.70710678118654746172f, 0011111111100110101000001001111001100110011111110011101111001100b
  mysin_new: 0.70710678118654746172f, 0011111111100110101000001001111001100110011111110011101111001100b

angle = 0.942478
  library  : 0.80901699437494745126f, 0011111111101001111000110111011110011011100101111111010010101000b
  mysin_old: 0.80901699437494734024f, 0011111111101001111000110111011110011011100101111111010010100111b
  mysin_new: 0.80901699437494734024f, 0011111111101001111000110111011110011011100101111111010010100111b

angle = 1.099557
  library  : 0.89100652418836778779f, 0011111111101100100000110010000000011101001111010010110001101100b
  mysin_old: 0.89100652418836767676f, 0011111111101100100000110010000000011101001111010010110001101011b
  mysin_new: 0.89100652418836767676f, 0011111111101100100000110010000000011101001111010010110001101011b

angle = 1.256637
  library  : 0.95105651629515353118f, 0011111111101110011011110000111000010011010001000101010011111111b
  mysin_old: 0.95105651629515353118f, 0011111111101110011011110000111000010011010001000101010011111111b
  mysin_new: 0.95105651629515353118f, 0011111111101110011011110000111000010011010001000101010011111111b

angle = 1.413717
  library  : 0.98768834059513777035f, 0011111111101111100110110010010010010100001011111110010001011100b
  mysin_old: 0.98768834059513777035f, 0011111111101111100110110010010010010100001011111110010001011100b
  mysin_new: 0.98768834059513777035f, 0011111111101111100110110010010010010100001011111110010001011100b

angle = 1.570796
  library  : 1.00000000000000000000f, 0011111111110000000000000000000000000000000000000000000000000000b
  mysin_old: 1.00000000000000022204f, 0011111111110000000000000000000000000000000000000000000000000001b
  mysin_new: 1.00000000000000000000f, 0011111111110000000000000000000000000000000000000000000000000000b

angle = 1.727876
  library  : 0.98768834059513777035f, 0011111111101111100110110010010010010100001011111110010001011100b
  mysin_old: 0.98768834059513777035f, 0011111111101111100110110010010010010100001011111110010001011100b
  mysin_new: 0.98768834059513777035f, 0011111111101111100110110010010010010100001011111110010001011100b

angle = 1.884956
  library  : 0.95105651629515364220f, 0011111111101110011011110000111000010011010001000101010100000000b
  mysin_old: 0.95105651629515364220f, 0011111111101110011011110000111000010011010001000101010100000000b
  mysin_new: 0.95105651629515375323f, 0011111111101110011011110000111000010011010001000101010100000001b

angle = 2.042035
  library  : 0.89100652418836789881f, 0011111111101100100000110010000000011101001111010010110001101101b
  mysin_old: 0.89100652418836800983f, 0011111111101100100000110010000000011101001111010010110001101110b
  mysin_new: 0.89100652418836800983f, 0011111111101100100000110010000000011101001111010010110001101110b

angle = 2.199115
  library  : 0.80901699437494745126f, 0011111111101001111000110111011110011011100101111111010010101000b
  mysin_old: 0.80901699437494756229f, 0011111111101001111000110111011110011011100101111111010010101001b
  mysin_new: 0.80901699437494756229f, 0011111111101001111000110111011110011011100101111111010010101001b

angle = 2.356194
  library  : 0.70710678118654757274f, 0011111111100110101000001001111001100110011111110011101111001101b
  mysin_old: 0.70710678118654768376f, 0011111111100110101000001001111001100110011111110011101111001110b
  mysin_new: 0.70710678118654757274f, 0011111111100110101000001001111001100110011111110011101111001101b

angle = 2.513274
  library  : 0.58778525229247324813f, 0011111111100010110011110010001100000100011101010101101001011111b
  mysin_old: 0.58778525229247324813f, 0011111111100010110011110010001100000100011101010101101001011111b
  mysin_new: 0.58778525229247324813f, 0011111111100010110011110010001100000100011101010101101001011111b

angle = 2.670354
  library  : 0.45399049973954685999f, 0011111111011101000011100010111000101011010001001101111000000010b
  mysin_old: 0.45399049973954685999f, 0011111111011101000011100010111000101011010001001101111000000010b
  mysin_new: 0.45399049973954691550f, 0011111111011101000011100010111000101011010001001101111000000011b

angle = 2.827433
  library  : 0.30901699437494750677f, 0011111111010011110001101110111100110111001011111110100101010001b
  mysin_old: 0.30901699437494745126f, 0011111111010011110001101110111100110111001011111110100101010000b
  mysin_new: 0.30901699437494745126f, 0011111111010011110001101110111100110111001011111110100101010000b

angle = 2.984513
  library  : 0.15643446504023097998f, 0011111111000100000001100000101101100111101010000101001101111001b
  mysin_old: 0.15643446504023095223f, 0011111111000100000001100000101101100111101010000101001101111000b
  mysin_new: 0.15643446504023095223f, 0011111111000100000001100000101101100111101010000101001101111000b

angle = 3.141593
  library  : 0.00000000000000012246f, 0011110010100001101001100000000000000000000000000000000000000000b
  mysin_old: 0.00000000000000023566f, 0011110010110000111110110010110111010110111000110001010101001000b
  mysin_new: 0.00000000000000023566f, 0011110010110000111110110010110111010110111000110001010101001001b

新的自适应方法与原始方法相比,赢了一些时间,平了大部分时间,输了一些其他时间。 (请注意,假设库方法 sin 精确到 double

我运行循环8次,如果你改善循环时间,它接近真实值。感谢@Sreeram TP

double sin(int x) {
    int tp=0;
    for(int k=1;k<8 ;k++)
    {
        tp+=pow(-1,k)*pow(x,2*k+1)/fact(2*k+1);
    }
    return tp;
}