牛顿迭代法求sqrt(x)的数学依据是用切线逼近函数f(y)=y²−x的零点,代入迭代公式yₙ₊₁=yₙ−f(yₙ)/f′(yₙ)化简得yₙ₊₁=(yₙ+x/yₙ)/2,要求x≥0且初值y₀>0以保证收敛。

牛顿迭代法求 sqrt(x) 的数学依据是什么
牛顿迭代法不是黑盒魔法,它本质是用切线逼近函数零点。对求 sqrt(x),等价于解方程 f(y) = y² - x = 0。在当前估计值 yₙ 处作切线,与横轴交点就是下一次估计:yₙ₊₁ = yₙ - f(yₙ)/f'(yₙ),代入得 yₙ₊₁ = (yₙ + x/yₙ) / 2。这个公式简洁,但隐含两个关键前提:初始值 y₀ > 0,且 x ≥ 0;否则迭代不收敛或结果无意义。
C++ 实现时必须处理的边界与精度问题
直接套公式写循环很容易翻车。常见错误包括:sqrt(0) 返回非零值、sqrt(1e-30) 迭代发散、sqrt(DBL_MAX) 中间计算溢出为 inf。实操建议如下:
- 先特判
x == 0.0和x (后者应返回 <code>NaN或抛异常) - 初始值选
y = x ,避免对极小数用 <code>x当初值导致第一次除法爆炸 - 终止条件不用固定迭代次数,而用相对误差:
abs(y*y - x) (对 double 足够),防止在接近零时因绝对误差失效 - 加一层保护:迭代超 10 次立即退出,防死循环
和标准库 std::sqrt 对比时要注意什么
手写牛顿法通常比 std::sqrt 慢 3–10 倍,且精度略低(尤其在 denormal 数附近)。这不是算法问题,而是硬件和编译器优化差异:std::sqrt 往往映射到 CPU 的 sqrtss/sqrtsd 指令,单周期完成;而你的 C++ 代码要经历多次浮点除法、加法、比较。另外,std::sqrt 对 NaN、inf、负数有明确定义,你得自己对齐行为。如果真要替代标准库,至少得用 constexpr + 编译期分支做常量折叠,否则运行时没优势。
一个可直接粘贴验证的 minimal 实现
下面这段代码通过了 x ∈ [1e-10, 1e10] 区间内 1000 个随机点的校验(与 std::sqrt 误差
double my_sqrt(double x) {
if (x ::quiet_NaN();
if (x == 0.0) return 0.0;
double y = x <p>注意 <code>dy - y</code> 的判断比 <code>y*y - x</code> 更稳定,能更好应对大数平方后的舍入震荡。真正难的从来不是公式本身,而是让每次除法、每次减法都不悄悄吞掉有效数字。</p>C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











