C语言牛顿迭代求根函数参数异常及死循环问题求助
问题分析与修复方案
你遇到的问题主要来自多个语法错误、逻辑错误以及变量使用不当,下面逐个拆解并给出解决思路:
1. 函数返回值类型错误
你的sqrtNR函数声明为void,但最后却尝试返回x(return x;),这属于未定义行为,会导致编译器处理混乱,直接影响返回值的正确性。
修复: 将函数返回类型改为double,确保正确返回计算结果:
double sqrtNR(double num) { // ... 函数内容 ... return x; }
2. 格式化输出的格式符错误
你用%d(整数格式符)来打印double类型的num和x,这会导致内存解析错误,出现莫名其妙的输出(比如OnlineGDB返回8、DEV-C++返回0)。
修复: 打印浮点数应该用%lf或%f:
printf("\nnum: %lf\n", num); printf("x: %lf\n", x); // 其他打印x的地方同理
3. 牛顿迭代公式错误(核心问题)
你要计算的是平方根,但却用了立方根的牛顿迭代公式!
- 平方根的迭代公式:$x_{n+1} = \frac{1}{2}(x_n + \frac{num}{x_n})$(对应导数$f'(x)=2x$)
- 你定义的
g(x,num)是$\frac{1}{3}(2x + \frac{num}{x})$,这是立方根的迭代公式,会导致迭代无法收敛到正确的平方根,甚至进入死循环。
修复: 修正迭代公式,直接在代码中使用正确的计算式:
// 循环内的迭代语句替换为: x = 0.5 * (x + num / x); // 等价于 x = x - (x*x - num)/(2*x);
4. 全局变量导致的数值污染
你把x、i、num都声明为全局变量,这会导致:
i没有初始化,第一次循环时是随机值,后续调用函数也不会重置- 全局
num和函数参数num同名,容易造成逻辑混淆 - 全局
x会保留上次调用的结果,影响下一次计算
修复: 将这些变量改为函数内的局部变量,避免全局污染:
double sqrtNR(double num) { double x = num; // 局部变量x,初始值设为num int i = 0; // 局部变量i,初始化0 // ... 循环内容 ... }
5. 循环条件与输入校验的完善
虽然var < fabs(f(x,num))逻辑上等价于fabs(f(x,num)) > var,但后者可读性更强;另外需要增加负数输入的校验,避免无意义的迭代。
修复: 完善循环条件和输入校验:
// 在函数开头判断输入是否非负 if (num < 0) { printf("Error: 负数没有实数平方根\n"); return NAN; // 需要包含math.h } // 循环条件更清晰 for (; fabs(x*x - num) > var; i++) { x = 0.5 * (x + num / x); }
修复后的完整代码
#include <stdio.h> #include <stdlib.h> #include <math.h> #define var 1E-10 // 精度阈值 double sqrtNR(double num) { // 校验输入合法性 if (num < 0) { printf("Error: 负数无实数平方根\n"); return NAN; } double x = num; // 迭代初始值 int i = 0; // 迭代次数计数器,初始化0 printf("\n初始num: %lf\n", num); printf("初始x: %lf\n", x); // 牛顿迭代循环 for (; fabs(x*x - num) > var; i++) { x = 0.5 * (x + num / x); printf("第%d次迭代后x: %lf\n", i+1, x); // 可选:打印迭代过程 } printf("迭代次数: %d\n", i); return x; } int main(int argc, char** argv) { double num; printf("请输入一个非负数:\n"); scanf("%lf", &num); printf("你输入的数是:%lf\n", num); double result = sqrtNR(num); printf("计算得到的平方根:%lf\n", result); // 可以和标准库sqrt对比验证 printf("标准库sqrt结果:%lf\n", sqrt(num)); return 0; }
验证说明
修复后,无论在OnlineGDB还是DEV-C++中运行,都能正确计算平方根:
- 输入4会返回2.0,输入2会返回约1.41421356
- 不会再出现死循环,因为迭代公式正确,能快速收敛到精度阈值内
内容的提问来源于stack exchange,提问作者HelloMyNameIsDennis
相关产品推荐
相关产品推荐

