牛顿迭代法求平方根最稳,核心解x²−n=0,迭代公式xₖ₊₁=(xₖ+n/xₖ)/2;需特判n=0、1,初值非零,用|Δx|控制精度。

用牛顿迭代法手写 sqrt 最稳
直接上牛顿法,它收敛快、实现简单、精度可控,比二分法更适合求平方根。核心是解方程 x² - n = 0,迭代公式为:x_{k+1} = (x_k + n / x_k) / 2。初始值取 n 或 n/2 都行,但别用 0(会除零)。
注意事项:
- 对
n == 0和n == 1单独返回,避免冗余迭代 - 用
fabs(x_next - x_curr) 做收敛判断,别用 <code>==比较浮点数 - 输入为负数时应提前返回
NaN或抛异常,C++ 中可返回std::numeric_limits<double>::quiet_NaN()</double> - 迭代次数通常 5–7 次就到 double 精度,不用设上限也基本安全
整数开方要小心溢出和边界
如果只要整数平方根(比如求 ≤√n 的最大整数),别套用浮点牛顿法再取整——static_cast<int>(sqrt(n))</int> 这种思路在没库函数时不可行,且浮点转整可能因舍入误差错一位。
推荐用二分查找,在 [0, n] 范围内找最大的 x 满足 x * x :
- 右边界别设成
n,对大数如INT_MAX,mid * mid会溢出;改用right = min(n, 46340)(因为46341² > INT_MAX) - 比较时写成
mid (整除)可规避乘法溢出,但要注意 <code>mid == 0时除零 - 最终结果就是
left - 1(标准二分结束时left是第一个不满足条件的位置)
double 输入下牛顿法的典型错误
常见翻车点不是算法本身,而是类型和边界处理:
- 用
float当迭代变量 → 中间精度丢失,收敛变慢甚至不收敛;一律用double - 没处理
n是inf或nan→ 迭代式产生nan后永远卡住;加一句if (isnan(n) || isinf(n)) return n; - 初始值选
n对极小数(如1e-100)效果差,此时n/2更好;更稳妥是取max(n, 1.0) - 收敛阈值设太大(如
1e-3)会导致低精度,太小(如1e-17)在某些平台可能陷入死循环(浮点抖动)
性能和可移植性提醒
自己写的 sqrt 几乎肯定比硬件指令或 glibc 的 sqrt 慢,别在热路径里用。但它的好处是:完全可控、无依赖、可嵌入裸机环境。
若目标平台有 sqrtss(x86)或 vsqrt(ARM NEON)指令,而你又在写底层数学库,那牛顿法通常只做 1–2 次迭代精修——初始猜测直接用指令粗算结果。这时候重点不是“怎么写”,而是“怎么跟汇编/内在函数对接”。
最易被忽略的是:不同平台对 DBL_EPSILON 和浮点舍入模式敏感,测试时至少覆盖 0.25、2.0、1e30、1e-30 这四类输入。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











