无幂运算与阶乘的泰勒展开版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
相关产品推荐
相关产品推荐

