CE7453 Numerical Algorithms 期末高分超详细攻略(第一章:Root Finding)

本章内容:方程求根(Root Finding)
适用对象:零基础/考前冲刺/快速查漏补缺
内容特色:详细原理、公式推导、算法流程、例题全解、英文关键词


1.1 基本概念与背景

  • 什么是方程求根?
    给定一个连续函数 ,我们想找到 使得 。这个 就叫做 的根(root)。

  • 数学表示
    求解方程 的解

  • 实际应用

    • 物理学:平衡点、临界值、交叉点计算
    • 工程学:结构稳定性分析、电路设计
    • 金融学:期权定价、收益率计算
    • 计算机图形学:曲线/曲面求交
    • 优化问题:目标函数的极值点(导数为零)
  • 求根方法分类

    • 直接法:代数方程的解析解(如一元二次方程公式)
    • 迭代法:通过迭代逼近根(本章重点)
    • 混合法:结合多种方法的优点

1.2 主要算法与原理

1.2.1 二分法(Bisection Method)

  • 原理
    如果连续函数 在区间 上满足 异号(即 ),根据中值定理,区间内必存在至少一个根。

  • 算法流程

    1. 检查 ,否则不能用二分法。
    2. 计算中点
    3. 判断 的符号:
      • 如果 ,找到精确根,返回
      • 如果 ,根在 ,令
      • 如果 ,根在 ,令
    4. 重复2-3,直到区间足够小()或迭代次数达到上限。
  • 收敛性分析

    • 每次迭代后,区间长度减半:
    • 经过 次迭代后,区间长度:
    • 要达到精度 ,需要迭代次数:
  • 误差估计

    • 是第 次迭代的中点,则 ,其中 是真实根。
    • 若要求解精确到小数点后 位,需满足
    • 精度要求:若要求解精确到小数点后 位,即误差小于 ,则需要满足:
    • 所需迭代次数:解上述不等式可得最小迭代次数 或更方便计算的形式:
  • 优缺点

    • 优点
      • 一定收敛(全局收敛性,global convergence)
      • 实现简单,稳定可靠
      • 不需要导数信息
    • 缺点
      • 收敛速度慢(线性收敛,收敛阶为1)
      • 每次迭代只减少一位有效数字
      • 只适用于区间端点异号的情况
      • 无法处理重根
  • 伪代码

    function Bisection(f, a, b, tol, max_iter)
        if f(a)*f(b) >= 0 then
            return "Error: 区间端点不异号"
        end if
        
        iter = 0
        while (b-a)/2 > tol and iter < max_iter do
            c = (a+b)/2
            if f(c) == 0 then
                return c  // 找到精确根
            else if f(a)*f(c) < 0 then
                b = c
            else
                a = c
            end if
            iter = iter + 1
        end while
        
        return (a+b)/2  // 返回区间中点作为近似根
    end function
    
  • 公式

  • 英文关键词:bisection method, bracket, interval halving, binary search, convergence, tolerance, error bound

例题1:二分法求解

问题:用二分法求 内的根,精度要求为

分析, ,符合二分法使用条件。 初始区间 ,区间长度为 1。 要求精度 。 需要满足 ,即 。 因为 , ,所以至少需要 次迭代。

迭代过程

n区间长度
0010.5-0.375[0.5, 1]0.5
10.510.750.171875[0.5, 0.75]0.25
20.50.750.625-0.130859[0.625, 0.75]0.125
30.6250.750.68750.012451[0.625, 0.6875]0.0625
40.6250.68750.65625-0.061012[0.65625, 0.6875]0.03125
50.656250.68750.671875-0.024755[0.671875, 0.6875]0.015625
60.6718750.68750.6796875-0.006270[0.6796875, 0.6875]0.0078125

结果:经过7次迭代,得到近似根 。此时区间长度为 ,满足精度要求。

Python代码示例

def is_close(a, b, rtol=1e-5, atol=1e-8):
    """
    检查两个数值是否足够接近,考虑浮点数精度问题
    """
    return np.abs(a - b) <= (atol + rtol * np.abs(b))

def test_example1_bisection():
    """
    验证例题1:用二分法求 f(x)=x^3+x-1 在 [0,1] 内的根,精度 10^-2
    文档中的答案:x ≈ 0.6796875
    """
    f = lambda x: x**3 + x - 1
    
    # 二分法实现
    def bisection_method(f, a, b, tol=1e-10, max_iter=100):
        if f(a) * f(b) >= 0:
            raise ValueError("区间端点函数值必须异号")
        
        iter_count = 0
        while (b - a) / 2 > tol and iter_count < max_iter:
            c = (a + b) / 2
            if f(c) == 0:
                return c
            elif f(a) * f(c) < 0:
                b = c
            else:
                a = c
            iter_count += 1
        
        return (a + b) / 2
    
    # 用自己实现的二分法计算
    root_bisection = bisection_method(f, 0, 1, tol=1e-2)
    # 用scipy的方法计算精确值
    root_exact = optimize.root_scalar(f, bracket=[0, 1], method='brentq').root
    
    # 文档中给出的答案
    root_document = 0.6796875
    
    # 验证自己实现的方法是否与文档答案一致
    # 这里我们只展示计算过程,验证部分在test文件中执行
    print(f"二分法计算结果: {root_bisection}")
    print(f"文档答案: {root_document}")
    print(f"Scipy精确解: {root_exact}")
    print(f"函数在文档答案处的值: {f(root_document)}")

# 运行示例 (需要 import numpy as np 和 from scipy import optimize)
# test_example1_bisection()

1.2.2 牛顿法(Newton's Method)

  • 原理
    利用函数的局部线性近似(泰勒展开)逐步逼近根。在当前点 处作切线,切线与 轴的交点作为下一个近似值

  • 数学推导
    处展开 的一阶泰勒级数:

    ,解得:

    这就是牛顿法的迭代公式:

  • 几何解释
    每次迭代相当于用切线近似函数,切线与 轴的交点作为下一个近似值。

  • 几何解释: 在点 处作函数 的切线,切线的方程为 。令 ,解出切线与 轴的交点横坐标,即为

  • 算法流程

    1. 选择初始值 (初值选择很重要!)
    2. 计算
    3. 计算
    4. 检查收敛条件:
      • (解的变化小)或
      • (函数值接近零)或
      • 达到最大迭代次数 则停止;否则 ,回到步骤2
    • 停止准则(Stopping Criteria): 迭代过程需要一个明确的停止条件,以避免无限循环并确保达到所需精度。常用准则包括:
      • 解的绝对误差。当连续两次迭代的解足够接近时停止。
      • 解的相对误差 (当 )。适用于解的数量级未知或变化较大时。
      • 函数值接近零。当函数值足够接近零时停止。
      • 达到最大迭代次数:设置一个迭代上限 max_iter,防止算法因不收敛或收敛过慢而无限运行。 实际应用中通常组合使用这些准则。
  • 收敛性分析

    • 若初值足够接近根,且 (非重根),则牛顿法具有二次收敛性(quadratic convergence)
    • 误差关系:,其中 为常数
    • 对于重根(),收敛阶降为线性
  • 优缺点

    • 优点
      • 收敛速度快(通常为二次收敛)
      • 每次迭代可使有效数字翻倍
      • 适用于高精度计算
    • 缺点
      • 需要计算导数
      • 初值选择敏感,可能不收敛或收敛到非预期根
      • 在导数接近零处可能不稳定
      • 对重根收敛较慢
  • 伪代码

    function Newton(f, f_prime, x0, tol_x, tol_f, max_iter)
        x = x0
        iter = 0
        
        while iter < max_iter do
            fx = f(x)
            if |fx| < tol_f then
                return x  // 函数值足够接近零
            end if
            
            fpx = f_prime(x)
            if fpx == 0 then
                return "Error: 导数为零,无法继续"
            end if
            
            x_new = x - fx/fpx
            if |x_new - x| < tol_x then
                return x_new  // 解的变化足够小
            end if
            
            x = x_new
            iter = iter + 1
        end while
        
        return "Warning: 达到最大迭代次数"
    end function
    
  • 英文关键词:Newton's method, Newton-Raphson method, tangent method, quadratic convergence, initial guess, derivative, root finding

例题2:牛顿法求解

问题:用牛顿法求 的正根,取初值 ,精度要求

分析 迭代公式:

迭代过程

结果,满足精度要求。近似根 。 (实际根为

Python代码示例

def test_example2_newton():
    """
    验证例题2:用牛顿法求 f(x)=x^2-2 的根,x₀=1,精度 10^-4
    文档中的答案:x ≈ 1.4142
    """
    f = lambda x: x**2 - 2
    df = lambda x: 2*x
    
    # 牛顿法实现
    def newton_method(f, df, x0, tol=1e-10, max_iter=100):
        x = x0
        for i in range(max_iter):
            fx = f(x)
            if abs(fx) < tol:
                return x
            
            dfx = df(x)
            if dfx == 0:
                raise ValueError("导数为零,牛顿法失效")
            
            x_new = x - fx / dfx
            if abs(x_new - x) < tol:
                return x_new
            
            x = x_new
        
        return x
    
    # 用自己实现的牛顿法计算
    root_newton = newton_method(f, df, 1, tol=1e-4)
    # 文档中给出的答案
    root_document = 1.4142
    # 精确值是根号2
    root_exact = np.sqrt(2)
    
    # 验证部分在test文件中执行
    print(f"牛顿法计算结果: {root_newton}")
    print(f"文档答案: {root_document}")
    print(f"精确解: {root_exact}")
    print(f"函数在文档答案处的值: {f(root_document)}")

# 运行示例 (需要 import numpy as np)
# test_example2_newton()

例题3:牛顿法求解

问题:用牛顿法求解 的根,取初始值

分析 迭代公式:

迭代过程

结果:迭代几次后,解趋于稳定。近似根

Python代码示例

def test_example3_newton():
    """
    验证例题3:用牛顿法求解 f(x) = e^x - x - 2 的根,初始值 x₀ = 1
    文档中的答案:x ≈ 1.146
    """
    f = lambda x: np.exp(x) - x - 2
    df = lambda x: np.exp(x) - 1
    
    # 使用上面的牛顿法实现
    root_newton = newton_method(f, df, 1, tol=1e-4)
    # 用scipy的方法计算精确值
    root_exact = optimize.root_scalar(f, x0=1, fprime=df, method='newton').root
    # 文档中给出的答案
    root_document = 1.146
    
    # 验证部分在test文件中执行
    print(f"牛顿法计算结果: {root_newton}") # 实际计算会更精确
    print(f"文档答案: {root_document}")
    print(f"Scipy精确解: {root_exact}")
    print(f"函数在文档答案处的值: {f(root_document)}")

# 运行示例 (需要 import numpy as np 和 from scipy import optimize, 以及上面的 newton_method 函数)
# test_example3_newton()

牛顿法求 的例题

问题:使用牛顿法计算 ,取初值

分析: 求 等价于求 的正根。 迭代公式:

迭代过程

结果:迭代3次后,得到近似根

Python代码示例

def test_sqrt3_newton():
    """
    验证牛顿法求 sqrt(3) 的例题
    文档中的答案:sqrt(3) ≈ 1.73205
    """
    f = lambda x: x**2 - 3
    df = lambda x: 2*x
    
    # 牛顿法迭代公式的简化版本
    def newton_sqrt3(x0, iterations=3):
        x = x0
        for _ in range(iterations):
            x = 0.5 * (x + 3/x)
        return x
    
    # 用简化的牛顿法计算(文档中的迭代过程)
    root_newton = newton_sqrt3(2, iterations=3)
    # 文档中给出的答案
    root_document = 1.73205
    # 精确值是根号3
    root_exact = np.sqrt(3)
    
    # 验证部分在test文件中执行
    print(f"简化牛顿法计算结果 (3次迭代): {root_newton}")
    print(f"文档答案: {root_document}")
    print(f"精确解: {root_exact}")

# 运行示例 (需要 import numpy as np)
# test_sqrt3_newton()

1.2.3 割线法(Secant Method)

  • 原理
    牛顿法的变种,用差商近似导数,避免显式计算导数。使用前两次迭代点连线的斜率代替导数。

  • 迭代公式

  • 数学推导
    用差商近似导数:

    代入牛顿法公式得到割线法公式。

  • 几何解释: 割线法用连接点 的割线来近似函数 。割线与 轴的交点即为下一个近似值

  • 算法流程

    1. 选择两个初始点
    2. 计算
    3. 检查收敛条件,若满足则停止;否则 ,回到步骤2
  • 收敛性分析

    • 收敛阶约为 (黄金分割比)
    • 介于线性收敛和二次收敛之间,称为超线性收敛(superlinear convergence)
  • 优缺点

    • 优点
      • 不需要计算导数
      • 收敛速度优于二分法
      • 每次迭代只需一次函数评估(牛顿法需要函数和导数)
    • 缺点
      • 收敛速度低于牛顿法
      • 需要两个初始点
      • 可能出现分母接近零的情况(两点函数值接近)
      • 收敛性不如二分法可靠
  • 伪代码

    function Secant(f, x0, x1, tol, max_iter)
        iter = 0
        
        while iter < max_iter do
            f0 = f(x0)
            f1 = f(x1)
            
            if |f1| < tol then
                return x1
            end if
            
            if f1 == f0 then
                return "Error: 分母为零,无法继续"
            end if
            
            x_new = x1 - f1*(x1-x0)/(f1-f0)
            
            if |x_new - x1| < tol then
                return x_new
            end if
            
            x0 = x1
            x1 = x_new
            iter = iter + 1
        end while
        
        return "Warning: 达到最大迭代次数"
    end function
    
  • 英文关键词:secant method, finite difference Newton, superlinear convergence, initial points

例题4:割线法求解

问题:用割线法求 的根,取初值

分析 迭代公式:

迭代过程

结果:迭代5次后,函数值非常接近零。近似根

Python代码示例

def test_secant_example():
    """
    验证割线法求 f(x)=x^3+x-1 的根的例题
    文档中的答案:x ≈ 0.6822 (文档计算过程有微小差异,取0.682)
    """
    f = lambda x: x**3 + x - 1
    
    # 割线法实现
    def secant_method(f, x0, x1, tol=1e-10, max_iter=100):
        for i in range(max_iter):
            f0, f1 = f(x0), f(x1)
            
            if abs(f1) < tol:
                return x1
            
            if f1 == f0:
                raise ValueError("割线法分母为零")
            
            x_new = x1 - f1 * (x1 - x0) / (f1 - f0)
            
            if abs(x_new - x1) < tol:
                return x_new
            
            x0, x1 = x1, x_new
        
        return x1
    
    # 用自己实现的割线法计算
    root_secant = secant_method(f, 0, 1, tol=1e-4)
    # 用scipy的方法计算精确值
    root_exact = optimize.root_scalar(f, bracket=[0, 1], method='brentq').root
    # 文档中给出的答案 (根据我们的计算是 0.682)
    root_document = 0.682
    
    # 验证部分在test文件中执行
    print(f"割线法计算结果: {root_secant}")
    print(f"文档答案 (按计算过程): {root_document}")
    print(f"Scipy精确解: {root_exact}")
    print(f"函数在文档答案处的值: {f(root_document)}")

# 运行示例 (需要 import numpy as np 和 from scipy import optimize)
# test_secant_example()

例题5:割线法求解

问题:用割线法求 的根,取初值

分析

迭代过程

结果:迭代几次后,解趋于稳定。近似根

Python代码示例

def test_cos_x_example():
    """
    验证割线法求 f(x) = cos(x) - x 的根的例题
    文档中的答案:x ≈ 0.739
    """
    f = lambda x: np.cos(x) - x
    
    # 使用上面的割线法实现
    root_secant = secant_method(f, 0.5, 1, tol=1e-4)
    # 用scipy的方法计算精确值
    root_exact = optimize.root_scalar(f, bracket=[0, 1], method='brentq').root
    # 文档中给出的答案
    root_document = 0.739
    
    # 验证部分在test文件中执行
    print(f"割线法计算结果: {root_secant}")
    print(f"文档答案: {root_document}")
    print(f"Scipy精确解: {root_exact}")
    print(f"函数在文档答案处的值: {f(root_document)}")

# 运行示例 (需要 import numpy as np 和 from scipy import optimize, 以及上面的 secant_method 函数)
# test_cos_x_example()

1.2.4 Regula Falsi 法(假位法)

  • 原理
    结合二分法的可靠性和割线法的快速收敛性。使用割线法确定下一个迭代点,但保持区间端点异号。

  • 迭代公式
    与割线法相同,但每次迭代后保留使函数值异号的区间。

  • 算法流程

    1. 初始区间 满足
    2. 计算割线法的下一个点
    3. ,则 ;否则
    4. 重复2-3直到收敛
  • 优缺点

    • 优点:结合了二分法的可靠性和割线法的快速收敛
    • 缺点:在某些情况下可能收敛缓慢
  • 英文关键词:regula falsi, false position method, bracketing method, hybrid method

1.2.5 Brent 方法

  • 原理
    结合二分法、割线法和反二次插值(inverse quadratic interpolation)的优点,是实际应用中最常用的求根方法之一。

  • 特点

    • 保证收敛(如二分法)
    • 在良好条件下快速收敛(如割线法)
    • 使用三点插值进一步加速收敛
    • MATLAB 的 fzero 函数和 Python 的 scipy.optimize.brentq 使用此方法
  • 英文关键词:Brent's method, inverse quadratic interpolation, guaranteed convergence, hybrid method


1.3 典型例题与详细解答

例题1:用二分法求 内的根,精度

解答步骤

  1. 检查端点:, ,满足 ,可用二分法。
  2. 第一次迭代:
    • ,根在
  3. 第二次迭代:
    • ,根在
  4. 第三次迭代:
    • ,根在
  5. 第四次迭代:
    • ,根在
  6. 检查精度:,继续迭代
  7. 第五次迭代:
    • ,根在
  8. 检查精度:,继续迭代
  9. 第六次迭代:
    • ,根在
  10. 检查精度:,继续迭代
  11. 第七次迭代:
    • ,根在
  12. 检查精度:,满足精度要求,停止迭代

答案,精确根约为 ,误差在允许范围内。


例题2:用牛顿法求 的根,,精度

解答步骤

  1. 计算 ,
  2. 第一次迭代:
    • ,
  3. 第二次迭代:
    • ,
  4. 第三次迭代:
    • ,
  5. 第四次迭代:
    • ,
  6. 检查精度:,满足精度要求

答案,即 的近似值。

收敛性分析

  • 第一次迭代:误差约
  • 第二次迭代:误差约 (误差平方级减小)
  • 第三次迭代:误差约 (继续平方级减小)
  • 体现了牛顿法的二次收敛特性

例题3:用牛顿法求解 的根,初始值

解答步骤

  1. 计算
  2. 第一次迭代:
  3. 第二次迭代:
  4. 第三次迭代:
    • 已经足够接近零,可以停止迭代

答案

验证,方程成立。


1.4 常见考点与易错点

  • 初值选择

    • 牛顿法对初值敏感,选择不当可能导致不收敛或收敛到非预期根
    • 二分法需要确保区间端点函数值异号
    • 割线法需要两个初始点,且不能使函数值相等
  • 收敛判断

    • 解的变化:
    • 函数值接近零:
    • 两种判断标准可能导致不同的停止时机
  • 收敛速度比较

    • 二分法:线性收敛(收敛阶为1)
    • 牛顿法:二次收敛(收敛阶为2)
    • 割线法:超线性收敛(收敛阶约为1.618)
  • 特殊情况处理

    • 重根问题:牛顿法对重根收敛较慢
    • 导数为零:牛顿法可能失效
    • 函数不连续:需要谨慎选择区间
  • 误差分析

    • 截断误差:由算法本身引入
    • 舍入误差:由计算机浮点运算引入
    • 两种误差的平衡考虑

1.5 实际应用案例

1.5.1 计算机图形学中的曲线求交

在计算机图形学中,求解两条参数曲线 的交点,可以转化为求解方程组:

这是一个二元非线性方程组,可以使用牛顿法的多维扩展(牛顿-拉夫森法)求解。

1.5.2 机器学习中的优化问题

在机器学习中,寻找损失函数的最小值点,需要求解梯度为零的方程:

这可以使用牛顿法或其变种(如拟牛顿法)求解。

1.5.3 物理模拟中的平衡点

在物理系统模拟中,寻找系统的平衡状态,往往需要求解力平衡方程:

这类问题通常使用牛顿法或混合方法求解。


1.6 英文术语对照表

中文术语英文术语
方程求根Root Finding
二分法Bisection Method
牛顿法Newton's Method / Newton-Raphson Method
割线法Secant Method
假位法Regula Falsi / False Position Method
收敛性Convergence
收敛阶Order of Convergence
线性收敛Linear Convergence
二次收敛Quadratic Convergence
超线性收敛Superlinear Convergence
全局收敛Global Convergence
局部收敛Local Convergence
误差估计Error Estimation
截断误差Truncation Error
舍入误差Round-off Error
迭代法Iterative Method
直接法Direct Method
混合法Hybrid Method