牛顿法求解过程的Python实现及其详解

什么是牛顿法?

牛顿法(Newton's Method),也称为牛顿-拉夫逊方法,是一种在实数域和复数域上近似求解方程的方法。这个方法利用函数的泰勒级数的前几项来寻找方程的根。

简单来说,牛顿法是一种通过不断逼近来找到函数零点(即方程的解)的方法。

Image

数学原理

对于一个连续可导的函数 f(x),希望找到满足 f(x) = 0 的 x 值。

牛顿法的基本思想是:

1.从一个初始猜测值 x₀ 开始2.在点 (xₙ, f(xₙ)) 处作函数的切线3.找到这条切线与 x 轴的交点 xₙ₊₁4.重复这个过程直到找到足够精确的解

数学公式推导:

•函数 f(x) 在点 xₙ 处的切线方程为:y = f'(xₙ)(x - xₙ) + f(xₙ)•当 y = 0 时,切线与 x 轴相交,此时:0 = f'(xₙ)(x - xₙ) + f(xₙ)•解得:x = xₙ - f(xₙ)/f'(xₙ)

因此,迭代公式为:

xₙ₊₁ = xₙ - f(xₙ)/f'(xₙ)

实际例子:求解 xeˣ - 2 = 0

在代码示例中,要解决的方程是:

f(x) = xeˣ - 2 = 0

这是一个无法通过代数方法直接求解的方程,所以使用牛顿法来近似求解。

1. 定义函数和导数

首先需要定义原函数及其导数:

def f(x):    return x * np.exp(x) - 2          # f(x) = x e^x - 2
def df(x):    return np.exp(x) * (1 + x)        # f'(x) = e^x (1 + x)

2. 选择初始值

选择一个好的初始猜测值对牛顿法很重要。在例子中,选择了 x₀ = 3。这个值是根据函数特性选择的,因为它靠近真实的根。

3. 迭代过程

按照牛顿法的公式进行迭代:

1.计算当前点的函数值 f(xₙ) 和导数值 f'(xₙ)2.应用公式计算下一个近似值:xₙ₊₁ = xₙ - f(xₙ)/f'(xₙ)3.检查是否收敛或达到最大迭代次数

代码实现详解

让逐步分析代码中的每个部分:

环境设置

import numpy as npimport matplotlibimport matplotlib.pyplot as pltfrom matplotlib.animation import FuncAnimationimport sys

这部分导入了必要的库:

numpy:用于高效的数值计算•matplotlib:用于数据可视化•FuncAnimation:用于创建动画效果•sys:用于系统相关的功能

牛顿法核心实现

x0 = 3             # 初始猜测值max_iter = 10      # 最大迭代次数xs = [x0]          # 存储每次迭代的结果
for _ in range(max_iter):    xn = xs[-1]           # 获取当前迭代点    fx, dfx = f(xn), df(xn)  # 计算函数值和导数值
    # 避免除零错误    if abs(dfx) < 1e-14:        print("导数太小,停止迭代")        break
    # 牛顿法公式    x_next = xn - fx / dfx    xs.append(x_next)     # 保存新的近似值

可视化部分

代码还包括了一个非常有用的可视化组件,以动画形式展示牛顿法的每一步:

1.绘制原函数曲线2.对于每一步迭代:

•显示当前点 (xₙ, f(xₙ))•绘制在该点的切线•显示下一个近似点的位置

这种可视化帮助直观地理解牛顿法的工作原理。

牛顿法的优点和缺点

优点

1.收敛速度快:在接近根时具有二次收敛速度2.精度高:能够获得很高精度的解3.适用性广:可用于求解各种类型的方程

缺点

1.需要导数:必须知道函数的导数,不会求导的我默默流泪2.初始值敏感:不好的初始值可能导致不收敛,第一次要猜得准3.可能失败:当导数为0时会失败

实际应用

牛顿法在科学计算和工程中有广泛的应用:

•求解非线性方程组•优化问题中的梯度下降•数值分析中的各种计算•机器学习中的参数优化

总结

牛顿法是一种强大而优雅的数值方法,通过简单的几何直观(切线逼近)解决了复杂的数学问题。虽然它的理论基础看起来有些复杂,但其实现却非常直观和高效。

通过Python实现,可以看到:

1.如何将数学公式转化为实际代码2.如何处理特殊情况(如导数为0)3.如何通过可视化增强对算法的理解

这种方法不仅在学术研究中非常重要,在实际工程应用中也非常有用。

完整代码

Image

"""牛顿法(Newton's Method)实现用于求解无解析解的方程"""
# 导入必要的库# numpy: 用于数值计算# matplotlib: 用于绘图# FuncAnimation: 用于创建动画# sys: 用于系统相关参数和函数import numpy as npimport matplotlibimport matplotlib.pyplot as pltfrom matplotlib.animation import FuncAnimationimport sys
# ========== 1. 设置后端避免 Qt 异常==========# 检查是否在 Linux 系统上运行如果是则设置 matplotlib 后端为 TkAgg# 这是为了避免在某些 Linux 系统上可能出现的 Qt 相关异常if sys.platform.startswith('linux'):    matplotlib.use('TkAgg')
# ========== 2. 自动配置中文字体 ==========# 定义一个函数来自动检测并设置可用的中文字体def set_chinese_font():    # 导入字体管理模块    import matplotlib.font_manager as fm
    # 定义可能的中文字体列表    chinese_fonts = [        'SimHei', 'Microsoft YaHei', 'WenQuanYi Zen Hei',        'Noto Sans CJK SC', 'FangSong', 'STSong'    ]
    # 获取系统中所有可用字体的名称集合    available = {f.name for f in fm.fontManager.ttflist}
    # 遍历中文字体列表查找第一个可用的字体    for font in chinese_fonts:        if font in available:            # 设置 matplotlib 使用该中文字体            plt.rcParams['font.sans-serif'] = [font]            # 解决负号显示问题            plt.rcParams['axes.unicode_minus'] = False            print(f"✅ 使用中文字体: {font}")            return
    # 如果没有找到中文字体则使用默认英文字体    print("⚠️ 未找到中文字体,使用英文界面")    plt.rcParams['font.sans-serif'] = ['DejaVu Sans']    plt.rcParams['axes.unicode_minus'] = True
# 调用函数设置字体set_chinese_font()
# ========== 3. 定义复杂函数无解析解==========# 定义目标函数 f(x) = x*e^x - 2# 这是一个无法通过代数方法直接求解的方程def f(x):    return x * np.exp(x) - 2          # f(x) = x e^x - 2
# 定义目标函数的导数 f'(x) = e^x * (1 + x)# 在牛顿法中需要使用导数来进行迭代计算def df(x):    return np.exp(x) * (1 + x)        # f'(x) = e^x (1 + x)
# ========== 4. 牛顿法迭代 ==========# 设置初始猜测值选择接近真实根的值可以加快收敛速度x0 = 3             # 初始猜测选在根附近比如 1.0
# 设置最大迭代次数防止无限循环max_iter = 10
# 创建一个列表存储每次迭代得到的 x 用于后续绘图和动画xs = [x0]
# 牛顿法迭代过程:# 根据公式 x_{n+1} = x_n - f(x_n)/f'(x_n) 进行迭代for _ in range(max_iter):    # 获取当前迭代点的 x 值    xn = xs[-1]
    # 计算当前点的函数值和导数值    fx, dfx = f(xn), df(xn)
    # 检查导数是否过小,避免除零错误    if abs(dfx) < 1e-14:        print("导数太小,停止迭代")        break
    # 应用牛顿法公式计算下一个近似根    x_next = xn - fx / dfx
    # 将新计算出的 x 值添加到列表中    xs.append(x_next)
# 输出最终结果print(f"最终近似根: x ≈ {xs[-1]:.10f}")print(f"验证 f(x) ≈ {f(xs[-1]):.2e}")
# ========== 5. 绘图范围(自动适应)==========# 根据迭代过程中产生的 x 值自动确定绘图范围x_min = min(xs + [0.0]) - 0.5x_max = max(xs + [2.0]) + 0.5
# 创建用于绘图的 x 值数组x_plot = np.linspace(x_min, x_max, 500)
# 计算对应的 y 值y_plot = f(x_plot)
# 创建图形和坐标轴对象fig, ax = plt.subplots(figsize=(9, 6))
# 绘制函数曲线ax.plot(x_plot, y_plot, 'b-', linewidth=2, label=r'$f(x) = x e^x - 2$')
# 绘制 x 轴和 y 轴ax.axhline(0, color='black', linewidth=0.8)ax.axvline(0, color='black', linewidth=0.8)
# 关闭网格显示ax.grid(False)  # 不要网格!
# 根据字体设置决定使用中文还是英文标签use_chinese = (plt.rcParams['axes.unicode_minus'] == False)
# 设置坐标轴标签和图形标题ax.set_xlabel('x')ax.set_ylabel('f(x)')ax.set_title('牛顿法求解无解析解方程' if use_chinese else 'Newton\'s Method for Non-analytic Equation')
# 添加图例ax.legend()
# 创建动画所需的图形元素# 当前点的标记point, = ax.plot([], [], 'ro', markersize=8)
# 切线的绘制tangent_line, = ax.plot([], [], 'r--', linewidth=1)
# 文本注释框用于显示迭代信息annotation = ax.text(0.02, 0.95, '', transform=ax.transAxes, fontsize=12,                     bbox=dict(boxstyle="round,pad=0.3", facecolor="yellow", alpha=0.7))
# ========== 6. 动画更新函数 ==========# 定义动画每一帧的更新函数def animate(i):    # 如果索引超出迭代次数则返回当前元素而不更新    if i >= len(xs):        return point, tangent_line, annotation
    # 获取当前迭代步骤的 x 值和对应的函数值    xn = xs[i]    yn = f(xn)
    # 更新当前点的位置    point.set_data([xn], [yn])
    # 绘制在当前点处的切线    # 切线方程: y = f'(xn)(x - xn) + f(xn)    x_tan = np.linspace(xn - 0.8, xn + 0.8, 100)    y_tan = df(xn) * (x_tan - xn) + yn    tangent_line.set_data(x_tan, y_tan)
    # 根据语言设置创建相应的文本说明    if use_chinese:        txt = f"第 {i} 步\nx = {xn:.6f}\nf(x) = {yn:.2e}"    else:        txt = f"Step {i}\nx = {xn:.6f}\nf(x) = {yn:.2e}"
    # 更新注释文本    annotation.set_text(txt)
    # 返回更新后的图形元素    return point, tangent_line, annotation
# ========== 7. 启动动画 ==========# 创建动画对象ani = FuncAnimation(fig, animate, frames=len(xs), interval=2000, blit=False, repeat=True)
# 显示图形try:    plt.show()except Exception as e:    print("图形界面不可用,仅输出结果。")
# 如果在 Jupyter Notebook 中运行可以使用以下代码显示 HTML 动画# HTML(ani.to_jshtml())

预览时标签不可点

Close

更多

Name cleared

微信扫一扫赞赏作者

Like the AuthorOther Amount

赞赏后展示我的头像

作品

暂无作品

Like the Author

Other Amount

¥

最低赞赏 ¥0

OK

Back

Other Amount

更多

赞赏金额

¥

最低赞赏 ¥0

1

2

3

4

5

6

7

8

9

0

.

Python语言程序设计 · 目录

Python语言程序设计

上一篇单一职责原则:写好Python函数的第一步下一篇梯形法求积分的Python实现

Close

更多

搜索「」网络结果

Close

调整当前正文文字大小

更多

100%