You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无幂运算与阶乘的泰勒展开版cos函数原理解析求助

泰勒展开实现s21_cos函数的逻辑解析

问题背景

我自己实现了基于泰勒展开的s21_cos函数,没有使用pow和阶乘运算,运行效果良好,但搞不懂实现原理——比如输入2时,迭代生成的项是约分后的分数形式(像8/12而非原泰勒展开项的16/24)。下面附上函数代码和输入2时的运行步骤输出,求解析该泰勒展开的实现逻辑。

实现代码

long double s21_cos(double x) {
  long double result;
  if (s21_isnan(x) || s21_isinf(x)) {
    result = NAN;  
  } else {
    // 将x归约到[-π, π]区间
    while (x > s21_M_PI) {
      x -= 2 * s21_M_PI;
    }
    while (x < -s21_M_PI) {
      x += 2 * s21_M_PI;
    }

    result = 1.0;
    long double term = 1.0;
    long double sign = -1.0;
    long double divident, divisor;
    int iteration_n = 1;
    printf("%Lf-", result);
    for (int n = 2; s21_fabs(term) > 1e-20; n += 2) {
      divident = x*x;
      divisor = (n*(n-1)); // 原代码拼写错误为devisor,此处修正为正确拼写
      
      term = term * divident / divisor;
      if(sign < 0)
        printf("+");
      else if(sign > 0)
        printf("-"); 
      result += sign * term;

      sign *= -1.0;
      iteration_n++;
    }
  }
  return result;
}

输入2时的运行步骤输出

1.000000-4.00000000000000000000/2.000000+8.00000000000000000000/12.000000-2.66666666666666666674/30.000000+0.35555555555555555557/56.000000-0.02539682539682539683/90.000000+0.00112874779541446208/132.000000-0.00003420447864892309/182.000000+0.00000075174678349282/240.000000-0.00000001252911305821/306.000000+0.00000000016377925566/380.000000-0.00000000000172399216/462.000000+0.00000000000001492634/552.000000-0.00000000000000010816/650.000000+0.00000000000000000067/756.000000

实现原理解析

1. 输入范围归约

余弦函数是周期为2π的偶函数,代码先把输入x调整到[-π, π]区间内。这么做是因为泰勒展开在x接近0时收敛速度最快,能减少迭代次数,同时避免x过大时高次幂项溢出。

2. 泰勒展开的递推优化

余弦函数的标准泰勒展开式为:
$$\cos(x) = \sum_{n=0}^{\infty} (-1)^n \frac{x^{2n}}{(2n)!} = 1 - \frac{x^2}{2!} + \frac{x^4}{4!} - \frac{x^6}{6!} + \dots$$

直接计算每一项需要算x^(2n)和(2n)!,不仅效率低还容易溢出。代码用递推式代替直接计算:

  • 初始项term = 1.0,对应展开式的第0项(n=0时的1)
  • 第k次迭代(对应展开式的第k项,n=k)的项,可以由前一项推导:
    $$term_{k} = term_{k-1} \times \frac{x^2}{(2k) \times (2k-1)}$$
    代码中n从2开始,每次加2,divisor = n*(n-1)正好对应(2k)*(2k-1),divident = x*x是公共的分子因子。这样每次只需要做一次乘法和一次除法,就得到当前项,自动完成了分数的约分(比如输入2时,第二项是4/2,第三项是(4/2)*4/(4*3) = 16/24 = 8/12,递推过程中已经完成了约分)。

3. 符号与结果累加

  • sign初始为-1.0,对应展开式第二项的负号,每次迭代后sign *= -1.0,实现交替加减的效果。
  • 每次迭代把sign * term加到结果result里,逐步累加得到余弦值。

4. 终止条件

当term的绝对值小于1e-20时停止迭代,因为此时项的大小已经远小于浮点数的精度范围,继续累加不会改变结果,保证了计算效率和精度。

内容的提问来源于stack exchange,提问作者Reckless Velociraptor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 02:50:25