用 Python 写一个会明确报告失败的牛顿迭代

为最简牛顿公式加入导数检查、有限数检查和迭代上限,并验证平方根计算。

先约定何时算完成

牛顿法每次用 x−f(x)/f′(x)x-f(x)/f'(x) 更新近似值。实现时需要说明成功的含义:下面以残差 ∣f(x)∣≤tol|f(x)|\le\mathrm{tol} 为返回条件,并给更新次数设置上限。残差小表示代回方程后的误差小;它与到真实根的距离并不总是相同,后者还受根附近导数大小的影响。

一个可以直接运行的版本

from math import isfinite, sqrt
 
 
def newton(f, df, x0, *, tol=1e-12,
           derivative_tol=1e-14, max_iter=50):
    if not isfinite(tol) or tol <= 0:
        raise ValueError("tol must be finite and positive")
    if not isfinite(derivative_tol) or derivative_tol <= 0:
        raise ValueError("derivative_tol must be positive")
    if not isinstance(max_iter, int) or max_iter < 0:
        raise ValueError("max_iter must be a nonnegative integer")
 
    x = float(x0)
    for iteration in range(max_iter + 1):
        if not isfinite(x):
            raise ArithmeticError("non-finite iterate")
        fx = float(f(x))
        if not isfinite(fx):
            raise ArithmeticError("non-finite function value")
        if abs(fx) <= tol:
            return x
        if iteration == max_iter:
            break
 
        dfx = float(df(x))
        if not isfinite(dfx) or abs(dfx) <= derivative_tol:
            raise ArithmeticError("derivative is too small or non-finite")
        x -= fx / dfx
 
    raise RuntimeError("iteration limit reached before convergence")
 
 
root = newton(lambda x: x * x - 2, lambda x: 2 * x, 1.0)
print(f"root = {root:.12f}")
print(f"absolute error = {abs(root - sqrt(2)):.3e}")

为什么保留这些检查

函数先判断残差,再检查导数,因此初值已经是根时可以直接返回。每次更新前检查导数,避免把一个很小的数放进分母;有限数检查则让溢出结果及时暴露。循环最多更新 max_iter 次,最后一次更新得到的点也会接受残差检查,不会少检查一步。

再试一次失败路径

把初值改为 0.0,求解 x2−2=0x^2-2=0 时会触发导数检查。这是有意义的反馈:此处切线水平,牛顿公式无法给出下一点。固定的导数阈值与残差阈值都依赖问题尺度,实际计算应结合变量和函数值的量级调整。若需要处理很远的初值,可以进一步研究阻尼牛顿法,或把牛顿步与区间方法结合。

这是一篇用于展示网站功能的示例,可替换为自己的学习笔记或真实项目记录。