基于麦克劳林级数的自制C语言sin函数返回NaN问题排查
问题分析与修复方案
你的正弦函数实现返回NaN,核心是两个关键问题:
1. 大数计算触发数值溢出与无意义运算
直接用麦克劳林级数计算pow(doub, odd)/factorial(odd)时,当输入值(比如55)较大、迭代次数(100次)偏多:
pow(55, 201)会超出double的数值表示范围,变成无穷大(inf)factorial(201)同样会突破double的精度上限,也变为无穷大- 无穷大除以无穷大的结果就是NaN(非数值)
另外你的factorial函数参数缺少类型声明(应写double factorial(int in)),虽不是NaN的直接原因,但会引发编译警告。
2. 未利用正弦函数的周期特性
麦克劳林级数仅在输入值接近0时收敛速度快,而55弧度远大于正弦函数的周期2π,直接计算会导致级数项先急剧膨胀再收缩,既低效又容易触发数值溢出。
修复后的代码
#include<stdio.h> #include<math.h> double sine(double x) { // 将输入值归约到[-π, π]范围,利用正弦的周期性 x = fmod(x, 2 * M_PI); if (x > M_PI) { x -= 2 * M_PI; } else if (x < -M_PI) { x += 2 * M_PI; } double sum = x; // 级数第一项为x double term = x; int sign = -1; // 递推计算后续项,避免重复计算pow和阶乘 for (int i = 1; i <= 20; i++) { // 20次迭代足够达到double精度 int denominator = 2 * i * (2 * i + 1); term *= x * x / denominator; sum += sign * term; sign = -sign; } return sum; } int main() { printf("%lf\n", sine(55)); // 可对比标准库结果:printf("%lf\n", sin(55)); return 0; }
核心优化点
- 角度归约:通过
fmod将输入映射到[-π, π],确保级数快速收敛,避免超大数计算 - 递推计算:每一项基于前一项推导,完全抛弃
pow和阶乘的重复计算,大幅提升数值稳定性 - 精简迭代次数:归约后的输入只需20次左右迭代,就能达到
double级别的精度,无需100次的冗余计算
内容的提问来源于stack exchange,提问作者Herblawunf
相关产品推荐
相关产品推荐

