C语言自定义mysqrt函数与标准sqrt函数计算结果不一致问题
问题分析与修复方案
结果差异的原因
- 标准库
sqrt()是极致优化的实现:多数编译器会直接调用CPU的硬件平方根指令(比如x86平台的FSQRT),或者用经过严格精度验证的算法,能输出double类型能表示的最精确平方根值。 - 你的迭代终止条件不合理:当前
while(n1 - n2 > 0)的逻辑有问题。因为浮点数精度有限,当迭代到接近真实值时,n1和n2会在两个相邻的double值之间来回跳动,此时n1 - n2会变成负数,循环直接终止,导致结果没收敛到最优精度。 - 浮点数不能直接用
==比较:哪怕两个值理论上相等,不同计算路径产生的二进制表示可能有细微差异,直接用相等判断完全不可靠。
具体修复步骤
1. 修正循环终止条件
把循环条件改成判断n1和n2的差值小于一个极小的阈值(比如1e-15,接近double的精度极限),确保迭代收敛到足够精度:
double mysqrt(double r) { double n1, n2; const double eps = 1e-15; // 匹配double的精度 n1 = r; n2 = 1.0; // 用绝对值差判断是否收敛 while (fabs(n1 - n2) > eps) { n1 = (n1 + n2) / 2.0; n2 = r / n1; } return n1; }
2. 改用合理的浮点数比较逻辑
main函数里别再用r1 == r2了,改成比较两者的差值是否在可接受范围内:
if (fabs(r1 - r2) < 1e-15) { printf("OK! Result = %.15lf\n", r1); } else { printf("!? r1 = %.15lf, r2 = %.15lf\n", r1, r2); }
注意:打印40位小数完全没意义——double类型最多只能精确表示15-17位有效数字,超出的部分都是无意义的尾数位。
3. 关于long double的问题
改成long double后仍有差异,是因为你没同步调整所有细节:
- 要改用
sqrtl()作为标准库对比函数 - 阈值要改成对应long double的精度(比如
1e-18) - 所有变量、字面量都要改成long double类型(比如
1.0L)
修改后的long double版本代码:
#include <stdio.h> #include <stdlib.h> #include <math.h> long double mysqrtl(long double r); int main() { long double r1, r2; const long double eps = 1e-18; r1 = sqrtl(2.0L); r2 = mysqrtl(2.0L); if (fabsl(r1 - r2) < eps) { printf("OK! Result = %.18Lf\n", r1); } else { printf("!? r1 = %.18Lf, r2 = %.18Lf\n", r1, r2); } return EXIT_SUCCESS; } long double mysqrtl(long double r) { long double n1, n2; const long double eps = 1e-18; n1 = r; n2 = 1.0L; while (fabsl(n1 - n2) > eps) { n1 = (n1 + n2) / 2.0L; n2 = r / n1; } return n1; }
修复后效果
调整完之后,你的实现结果会和标准库结果在对应浮点数类型的精度范围内完全一致,打印时保留对应有效位数即可(double取15位,long double取18位)。
内容的提问来源于stack exchange,提问作者WinterWeb
相关产品推荐
相关产品推荐

