Taylor级数(Maclaurin)计算sin(x)出现-nan问题求助
麦克劳林级数实现sin(x)时出现NaN的问题解决
我用麦克劳林级数实现sin(x)的计算公式:
$$\sin(x) = \sum_{n=0}^{\infty} \frac{(-1)^n x^{2n+1}}{(2n+1)!} = x - \frac{x^3}{3!} + \frac{x^5}{5!} - \frac{x^7}{7!} + \cdots$$
当输入起始值1、结束值20、步长2时,控制台在x=9之后开始输出-nan:
- x=9时,sin(x)=0.412118,泰勒级数结果为0.412118;
- x=11时,sin(x)=-0.99999,泰勒级数结果为-0.999976;
- x=13时,sin(x)=0.420167,泰勒级数结果为-nan。
需要解决这个问题用于实验作业,原实现代码如下:
#include <stdio.h> #include <math.h> int main(void) { float a, b, left, right, eps = 0.00001, step, x, add = 1, chis, znam, fact, sum = 0, delta; printf("Plese enter your start: "); scanf("%f", &a); printf("Your end: "); scanf("%f", &b); printf("and step: "); scanf("%f", &step); if (b < a || a < eps) { printf("Your inputs aren't correct"); return -1; } printf(" X sin(x) Taylor Delta\n"); for (x = a; x < b; x += step) { printf(" x = %9f ", x); left = sin(x); printf("%9f", left); chis = -x; znam = 1; sum = 0; add = 1; fact = 1; while (fabs(add) > eps) { add = -1 * chis / znam; sum += add; chis *= -1 * (x * x); fact++; znam *= fact * (fact + 1); fact++; } printf(" %9f ", sum); printf("%e\n", fabs(left - sum)); } }
问题原因分析
- 数值溢出:当x较大时,原代码中分母
znam通过不断乘递增的阶乘项,float类型精度有限,会快速溢出到无穷大,后续计算chis/znam时就会产生NaN。 - 未利用三角函数周期性:sin(x)是周期为2π的函数,直接对大x值计算泰勒级数,级数项数值会急剧增大,不仅收敛慢,还极易触发数值溢出。
- 递推逻辑隐患:原代码的初始值设置和递推方式绕了弯路,小x值下能得到正确结果,但大x值下会加速数值溢出的发生。
解决方案及修正代码
核心优化点
- 利用三角函数周期性,将x映射到[-π, π]区间,大幅降低计算时的x值;
- 改用递推方式计算级数项,避免直接计算大数阶乘,减少溢出风险;
- 替换float为double,提升数值计算的精度和抗溢出能力;
- 修正循环条件和初始值,让逻辑更清晰合理。
修正后的代码
#include <stdio.h> #include <math.h> int main(void) { double a, b, left, eps = 1e-5, step, x, add, sum, delta; const double PI = acos(-1.0); printf("请输入起始值: "); scanf("%lf", &a); printf("请输入结束值: "); scanf("%lf", &b); printf("请输入步长: "); scanf("%lf", &step); if (b < a) { printf("输入参数不正确\n"); return -1; } printf(" x sin(x) Taylor Delta\n"); for (x = a; x <= b; x += step) { // 将x映射到[-π, π]区间,利用sin的周期性 double x_mod = fmod(x, 2 * PI); if (x_mod > PI) { x_mod -= 2 * PI; } else if (x_mod < -PI) { x_mod += 2 * PI; } printf("x = %9lf ", x); left = sin(x); printf("%9lf", left); // 麦克劳林级数递推计算:首项为x_mod,后续项由前一项递推得到 sum = x_mod; add = x_mod; int n = 1; while (fabs(add) > eps) { // 递推公式:第n+1项 = 第n项 * (-x²) / [(2n)(2n+1)] add *= -x_mod * x_mod / ((2 * n) * (2 * n + 1)); sum += add; n++; } printf(" %9lf ", sum); delta = fabs(left - sum); printf("%e\n", delta); } return 0; }
效果验证
修正后的代码在输入起始值1、结束值20、步长2时,所有x值都能输出正确的泰勒级数结果,不会出现NaN,且计算精度符合设定的eps=1e-5要求。
内容的提问来源于stack exchange,提问作者KonstantaV
相关产品推荐
相关产品推荐

