关于一元方程求根中牛顿迭代法的分析

news2024/11/15 15:55:47

文末含有程序源代码以及可执行exe文件,文中部分内容参考网上博客以及GPT协助,希望能对你有所帮助~

一、理论知识简述

牛顿迭代法(Newton’s Method),也称为牛顿-拉弗森方法(Newton-Raphson Method),是一种用于寻找函数零点或者说方程的根的迭代数值方法。它是一种非常有效的数值分析技术,具有收敛速度快的特点,通常用于求解实数域上的非线性方程,特别是在科学和工程领域中经常遇到的问题。

牛顿迭代法的基本思想是通过不断地逼近函数零点来求解方程。其迭代过程如下:

  1. 初始值选择:选择一个初始猜测值 ( x0 ) 作为函数的根的近似值。

  2. 迭代公式:根据函数的导数和当前的猜测值,使用牛顿迭代公式进行迭代计算: x n + 1 = x n − f ( x n ) f ′ ( x n ) x_{n+1} = x_n - \frac{f(x_n)}{f'(x_n)} xn+1=xnf(xn)f(xn)

  3. 迭代更新:重复步骤2,实际中 x n + 1 = x n x_{n+1}=x_n xn+1=xn可能永远达不到,可根据给定的条件进行判断,迭代到满足停止迭代的条件,如达到指定的精度要求 ∣ x n + 1 − x n ∣ < △ |x_{n+1}-x_n|<△ xn+1xn<或达到最大迭代次数,此时的 x n + 1 x_{n+1} xn+1即为所求。

迭代公式简单推导:

假设 f(x) 是关于x的函数,求出 f(x) 的一阶导,即斜率:

f ′ ( x n ) = △ y △ x = f ( x n ) − 0 x n − x n + 1 = 0 − f ( x n ) ( x n + 1 − x n ) f'(x_n) = \frac{△y}{△x} = \frac{f(x_n) - 0}{x_n - x_{n+1}} = \frac{0 - f(x_n)}{(x_{n+1}-x_n)} f(xn)=xy=xnxn+1f(xn)0=(xn+1xn)0f(xn)

简化等式即可得到迭代公式:

x n + 1 = x n − f ( x n ) f ′ ( x n ) x_{n+1} = x_n - \frac{f(x_n)}{f'(x_n)} xn+1=xnf(xn)f(xn)

然后便可以利用得到的最终式进行迭代运算直到求到一个比较精确的值
在这里插入图片描述

Newton迭代法的几何解释:

方程 f(x) = 0 的根 x ∗ x^* x 为 y = f(x) 和 y = 0 (即x轴)的交点,设 x k x_k xk x ∗ x^* x 的某个初始近似值,过 P k P_k Pk 点 ( x k x_k xk , f ( x k ) f(x_k) f(xk) ) 作 y = f(x) 的切线交 x 轴于 x k + 1 x_{k+1} xk+1,即为所求得的近似值。继续过 P k + 1 P_{k+1} Pk+1 点 ( x k + 1 x_{k+1} xk+1 f ( x k + 1 ) f(x_{k+1}) f(xk+1) ) , P k + 2 P_{k+2} Pk+2 点 ( x k + 2 x_{k+2} xk+2 f ( x k + 2 ) f(x_{k+2}) f(xk+2) ),···,作 y = f(x) 的切线,即可逐步逼近精确的根 x ∗ x^* x 。因此,Newton法也叫切线法,因为它是沿着曲线 y = f (x) 上某一点作切线逐步外推逼近的。从 P K P_K PK 点作切线与x轴的交点 x k + 1 x_{k+1} xk+1,由于 y = f(x) 不是直线,所以 f ( x k + 1 ) f (x_{k+1}) f(xk+1) 就不可能为零。因此必须以 x k + 1 x_{k+1} xk+1 作为新的起点,从与之对应的 P k + 1 P_{k+1} Pk+1 点继续作切线,重复上述步骤,直至 f ( x k + 1 ) f(x_{k+1}) f(xk+1) 充分小,逼近零时为止。
在这里插入图片描述

牛顿迭代法具有如下特点:

  • 收敛性:在满足一定条件下,牛顿迭代法通常具有二阶收敛性,即每次迭代后,误差的平方将减小为原来的四分之一。

  • 初值敏感性:牛顿迭代法对初始猜测值 ( x0 ) 的选择十分敏感,不同的初始值可能会导致不同的迭代结果,甚至可能出现发散的情况。

  • 局部收敛:牛顿迭代法只能保证在初始猜测值附近的某个范围内收敛到函数的一个根,如果初始猜测值距离根较远,可能导致迭代过程不收敛或收敛到错误的根。

二、实现算法介绍

牛顿迭代法核心算法实现逻辑:

from sympy import *
# 定义变量
x = Symbol('x')
# 解析输入的函数函数
self.f_expr = eval(self.function_entry.get())
# 使函数可调用
self.f = lambdify(x, self.f_expr)
# 求函数的一阶导数
self.df_expr = diff(self.f_expr, x)
# 使函数可调用
self.df = lambdify(x, self.df_expr)

# 牛顿法(输入三个参数,初始猜值、误差、最大迭代次数)
def Newton(self, x0, E, max_count=100):
    # 存放迭代过程中的所有解
    ans_list = [x0] 
    # 最大迭代次数,避免死循环
    for i in range(max_count):  
        # 迭代公式
        ans_list.append(ans_list[i] - self.f(ans_list[i]) / self.df(ans_list[i]))  
        # 判断是否满足误差要求,达到直接中止迭代
        if abs(ans_list[i + 1] - ans_list[i]) <= E:
            break
    # 返回最终迭代结果,迭代次数,迭代过程全解
    return ans_list[i + 1], i + 1, ans_list

核心代码讲解:

  • from sympy import * 将 SymPy 中所有的功能都导入到当前命名空间中,包括常用的数学函数、符号、表达式、方程、矩阵等。这样一来,你可以直接使用这些功能而不用再使用 sympy. 这样的前缀。

  • x = sp.Symbol('x'):定义一个符号变量 x,用于表示函数中的自变量。

  • self.f_expr = eval(self.function_entry.get()):从用户输入的字符串中解析函数表达式。假设用户在界面上输入了一个函数表达式,通过 self.function_entry.get() 获取用户输入的字符串,然后通过 eval() 函数将其解析成可执行的Python代码,将结果存储在 self.f_expr 中。

  • self.f = sp.lambdify(x, self.f_expr):使用 sp.lambdify() 函数将SymPy表达式 self.f_expr 转换为一个可调用的函数 self.f。这样做是为了将SymPy的符号表达式转换为可以在数值计算中使用的函数。

  • self.df_expr = sp.diff(self.f_expr, x):求解函数 self.f_expr 对变量 x 的一阶导数。sp.diff() 函数用于对表达式求导。

  • self.df = sp.lambdify(x, self.df_expr):将一阶导数 self.df_expr 转换为一个可调用的函数 self.df

  • def Newton(self, x0, E, max_count=100)::定义一个名为 Newton 的方法,用于执行牛顿迭代法。

  • ans_list = [x0]:初始化一个列表 ans_list,用于存放迭代过程中的所有解,并将初始猜测值 x0 添加到列表中。

  • for i in range(max_count)::使用 for 循环迭代最多 max_count 次,避免死循环。

  • ans_list.append(ans_list[i] - self.f(ans_list[i]) / self.df(ans_list[i])):根据牛顿迭代法的公式更新迭代解。迭代公式即为 x k + 1 = x k − f ( x k ) f ′ ( x k ) x_{k+1} = x_k - \frac{f(x_k)}{f'(x_k)} xk+1=xkf(xk)f(xk),其中 self.f(ans_list[i]) 表示函数在点 ans_list[i] 处的函数值,self.df(ans_list[i]) 表示函数在点 ans_list[i] 处的导数值。

  • if abs(ans_list[i + 1] - ans_list[i]) <= E::判断迭代结果与上一次迭代结果之间的差值是否小于等于给定的误差 E,如果满足条件则跳出循环,迭代结束。

  • return ans_list[i + 1], i + 1, ans_list:返回迭代过程中最终得到的近似根 ans_list[i + 1]、迭代次数 i + 1,以及整个迭代过程中的所有解 ans_list,用作与界面渲染数据源。

算法流程图:

在这里插入图片描述

三、作品实现展示

1)运行程序的两种方式:可以在Python环境下运行Newton.py源文件或者直接双击运行Newton.exe程序。

2)运行程序的效果如下:
在这里插入图片描述

3)主体模块介绍:程序的第一行为相关数据输入框,第二行为相关操作按钮,第三行分别为函数图像、迭代值变化趋势图像,第四行为迭代值、迭代次数显示区。以下是每个输入框和按钮的作用以及输入函数的格式要求,可在程序中通过使用帮助查看:

  • 函数表达式输入框:
    请输入一个数学函数表达式,例如: x ∗ ∗ 2 + 3 x − 5 、 s p . e x p ( x ) + 10 x − 2 x**2+3x-5、sp.exp(x)+10x-2 x2+3x5sp.exp(x)+10x2
    表达式应当符合python语法,如加法(+), 减法(-), 乘法(*), 除法(/), 幂(**)。
    特殊函数输入格式请参考SymPy官方文档,例如 e x e^x ex => exp(x),sin(x) => sin(x)

    SymPy官方文档:https://docs.sympy.org/latest/tutorials/intro-tutorial/index.html#intro-tutorial

    Python语法学习:https://blog.csdn.net/m0_66570338/article/details/128714062

  • 初始猜测值输入框:
    输入一个初始猜测值,作为迭代计算的起始点。
    可以输入整数或小数。

  • 误差输入框:
    输入一个用于判断迭代精度的误差值。
    当迭代结果与上一次迭代结果的差值小于误差时,迭代停止。

  • 显示精度位输入框:
    设置迭代过程中结果的显示精度位数。
    输入一个正整数,表示显示结果的小数位数。

  • 最大迭代次数输入框:
    设置最大迭代次数,以避免迭代无限循环。
    输入一个正整数,表示最大的迭代次数。

  • 绘制函数按钮:
    根据输入的函数表达式,绘制函数图像。

  • 逐步迭代按钮:
    逐步展示迭代过程的图像,并显示每次迭代的结果。

  • 一键迭代按钮:
    一次性展示所有迭代过程的图像,并显示最终的迭代结果。

  • 重置程序按钮:
    重置所有的操作记录,清空输入框和图像区域,恢复到初始状态。

4)首先按照输入格式规范为每个输入框输入初始值:
在这里插入图片描述

5)首先点击绘制函数按钮,程序将检测初始值输入是否有误:

如果输入有误程序将拦截后续操作:

在这里插入图片描述

如果无误将绘制函数表达式图像,同时解锁逐步迭代、一键迭代操作按钮:

在这里插入图片描述

6)可以选择逐次点击逐步迭代按钮一步步查看迭代过程值变化情况:

在这里插入图片描述

在这里插入图片描述

7)也可以点击一键迭代按钮,立即查看整个迭代过程和迭代结果:

在这里插入图片描述

8)如果修改了任意输入框中的值函数图像和迭代结果都将清空,需要重新绘制函数,这是为了重复检查输入值正确性。

在这里插入图片描述

9)可以点击重置按钮,将清空所有值

在这里插入图片描述

10)可以点击使用帮助,可借此查看程序相关使用说明:

在这里插入图片描述

11)使用小技巧:由于迭代点、切线变化可能会比较散乱或者比较密集不便于查看,由此可以尝试长按鼠标拖动查看图像或者通过滚轮放大或缩小图像查看效果。

在这里插入图片描述

通过滚轮放大后查看效果:

在这里插入图片描述

如此用起来便方便很多~

四、知识应用讨论

牛顿迭代法及其类似思路在实际工程问题中有着广泛的应用,特别是在需要解决非线性方程、优化问题或者求解数值逼近的情况下。以下是一些典型的应用领域:

  1. 电力系统分析:在电力系统工程中,牛顿迭代法被广泛应用于潮流计算。电力系统是一个复杂的网络,包含各种各样的电力设备,如发电机、变压器、线路等。潮流计算是电力系统分析中的核心问题之一,其主要目的是计算电力系统中各节点的电压和相角,以确定电力系统的稳态工作状态。由于电力系统的非线性特性,潮流计算问题可以建模为一个非线性方程组,其中包含了大量的功率平衡方程和节点电压方程。牛顿迭代法可以应用于求解这些非线性方程组,以实现电力系统的潮流计算。未来随着电力系统的智能化和高效化发展,牛顿迭代法在电力系统工程中的应用也将更加广泛,可能会涉及到电力系统的实时运行优化、智能调度等方面。

  2. 结构工程:在结构工程中,牛顿迭代法被广泛应用于结构分析和设计。结构工程涉及到建筑物、桥梁、飞机等各种结构的设计和分析,其中包含了大量的非线性问题,如弹性力学、塑性力学、非线性材料等。牛顿迭代法可以应用于求解这些非线性问题,以确定结构的受力状态、变形情况或者稳定性分析。未来随着结构工程的发展,牛顿迭代法可能会在更复杂的结构分析和设计中得到应用,比如在微观尺度下考虑材料的非线性行为、多物理场耦合等方面。

  3. 控制系统设计:在控制工程中,牛顿迭代法被应用于控制系统的设计和优化。控制工程涉及到控制系统的建模、分析和设计,其中包含了大量的非线性问题,如非线性控制、非线性系统等。牛顿迭代法可以应用于求解这些非线性问题,以确定控制系统的参数或者设计控制策略。未来随着控制工程的发展,牛顿迭代法可能会在自适应控制、模糊控制、深度学习控制等方面发挥更重要的作用。。

  4. 结构力学分析:在结构力学中,需要解决非线性的力学方程,如弹性力学、塑性力学等。牛顿迭代法可以用于求解这些非线性方程,以确定结构的受力状态、变形情况或者稳定性分析。

  5. 信号处理:在信号处理领域,有时需要求解非线性方程来实现信号的滤波、降噪或者分析。牛顿迭代法可以应用于这些问题的求解,以实现对信号的处理与分析。

  6. 数值优化:牛顿迭代法也可以用于求解优化问题,特别是在数值优化中,需要最小化或者最大化目标函数的情况下。通过求解目标函数的导数和二阶导数,可以利用牛顿迭代法来寻找最优解。

随着科学技术的不断进步和工程领域的不断发展,牛顿迭代法在实际工程问题中的应用前景是十分广阔的。未来我们可以期待牛顿迭代法在工程领域中的应用更加普遍和深入,可能会涉及到更多领域的问题求解和优化,比如在智能交通系统、智能制造系统、智能能源系统等方面的应用。同时,随着计算机硬件和软件技术的不断发展,牛顿迭代法的计算效率和稳定性也会得到进一步提高,为工程领域的应用提供更加可靠和高效的解决方案。因此,牛顿迭代法作为一种强大的数值方法,将继续在工程领域中发挥重要作用,推动工程技术的进步和发展。

五.可执行文件和源代码

源代码Gitee仓库地址:牛顿迭代法演示程序源代码-Gitee仓库地址
代码:

"""
@author: 观止
@complete: 2024-06-08
"""
import sys

import matplotlib.pyplot as plt
import numpy as np
from PyQt5.QtWidgets import (
    QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
    QLabel, QLineEdit, QPushButton, QTextEdit, QMessageBox,
)
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from sympy import *

plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号


class FunctionPlotterApp(QMainWindow):
    function_placeholder = "请输入,参考使用帮助"
    initial_guess_placeholder = "请输入,例如0"
    error_placeholder = "请输入,例如0.0005"
    precision_placeholder = "请输入,例如8"
    max_placeholder = "请输入,例如10"

    def __init__(self):
        super().__init__()
        self.setWindowTitle("关于一元方程求根中牛顿迭代法的分析")

        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        layout = QVBoxLayout(central_widget)

        # 输入框布局
        input_layout = QHBoxLayout()
        layout.addLayout(input_layout)

        # 函数输入框
        self.function_entry = QLineEdit(self)
        self.function_entry.setPlaceholderText(self.function_placeholder)
        self.function_entry.textChanged.connect(self.reset_button_and_image)
        input_layout.addWidget(QLabel("函数表达式:"))
        input_layout.addWidget(self.function_entry)

        # 初始猜测值输入框
        self.initial_guess_entry = QLineEdit(self)
        self.initial_guess_entry.setPlaceholderText(self.initial_guess_placeholder)
        self.initial_guess_entry.textChanged.connect(self.reset_button_and_image)
        input_layout.addWidget(QLabel("初始猜测值:"))
        input_layout.addWidget(self.initial_guess_entry)

        # 误差输入框
        self.error_entry = QLineEdit(self)
        self.error_entry.setPlaceholderText(self.error_placeholder)
        self.error_entry.textChanged.connect(self.reset_button_and_image)
        input_layout.addWidget(QLabel("误差:"))
        input_layout.addWidget(self.error_entry)

        # 显示精度位输入框
        self.precision_entry = QLineEdit(self)
        self.precision_entry.setPlaceholderText(self.precision_placeholder)
        self.precision_entry.textChanged.connect(self.reset_button_and_image)
        input_layout.addWidget(QLabel("显示精度位:"))
        input_layout.addWidget(self.precision_entry)

        # 最大迭代次数输入框
        self.max_entry = QLineEdit(self)
        self.max_entry.setPlaceholderText(self.max_placeholder)
        self.max_entry.textChanged.connect(self.reset_button_and_image)
        input_layout.addWidget(QLabel("最大迭代次数:"))
        input_layout.addWidget(self.max_entry)

        # 按钮布局
        button_layout = QHBoxLayout()
        layout.addLayout(button_layout)

        # 绘制函数按钮
        self.start_button = QPushButton("绘制函数")
        self.start_button.clicked.connect(self.start_plot_function)
        button_layout.addWidget(self.start_button)

        # 逐步迭代按钮
        self.iterate_button = QPushButton("逐步迭代")
        self.iterate_button.clicked.connect(lambda: self.plot_iteration(False))
        self.iterate_button.setEnabled(False)
        button_layout.addWidget(self.iterate_button)

        # 一键迭代按钮
        self.show_result_button = QPushButton("一键迭代")
        self.show_result_button.clicked.connect(lambda: self.plot_iteration(True))
        self.show_result_button.setEnabled(False)
        button_layout.addWidget(self.show_result_button)

        # 使用帮助按钮
        self.help_button = QPushButton("使用帮助")
        self.help_button.clicked.connect(self.show_help)
        button_layout.addWidget(self.help_button)

        # 重置程序按钮
        self.reset_button = QPushButton("重置程序")
        self.reset_button.clicked.connect(self.reset_option)
        button_layout.addWidget(self.reset_button)

        # 图形显示布局
        graph_layout = QHBoxLayout()
        layout.addLayout(graph_layout)

        # 第一个绘图区域
        self.figure1 = plt.figure(figsize=(6, 4))
        self.canvas1 = FigureCanvas(self.figure1)
        graph_layout.addWidget(self.canvas1)
        layout.setStretchFactor(self.canvas1, 10)  # 设置画布在布局中的拉伸因子
        # 连接画布的事件到相应的方法
        self.canvas1.mpl_connect("scroll_event", self.zoom)
        self.canvas1.mpl_connect("button_press_event", self.on_press)
        self.canvas1.mpl_connect("button_release_event", self.on_release)
        self.canvas1.mpl_connect("motion_notify_event", self.on_motion)
        self.dragging = False  # 设置拖动标志
        self.last_mouse_pos = None  # 初始化上一个鼠标位置

        # 第二个绘图区域
        self.figure2 = plt.figure(figsize=(6, 4))
        self.canvas2 = FigureCanvas(self.figure2)
        graph_layout.addWidget(self.canvas2)

        # 迭代结果显示框
        self.iteration_result_text = QTextEdit()
        layout.addWidget(self.iteration_result_text)

    def adjust_axes(self):  # 定义调整坐标轴范围的方法
        xlim = self.ax1.get_xlim()  # 获取 x 轴范围
        ylim = self.ax1.get_ylim()  # 获取 y 轴范围
        x_range = xlim[1] - xlim[0]  # 计算 x 轴范围
        y_range = ylim[1] - ylim[0]  # 计算 y 轴范围
        if x_range > y_range:  # 若 x 轴范围大于 y 轴范围
            y_center = (ylim[1] + ylim[0]) / 2  # 计算 y 轴中心
            new_y_range = x_range  # 新的 y 轴范围为 x 轴范围
            self.ax1.set_ylim(y_center - new_y_range / 2, y_center + new_y_range / 2)  # 设置新的 y 轴范围
        else:  # 若 y 轴范围大于等于 x 轴范围
            x_center = (xlim[1] + xlim[0]) / 2  # 计算 x 轴中心
            new_x_range = y_range  # 新的 x 轴范围为 y 轴范围
            self.ax1.set_xlim(x_center - new_x_range / 2, x_center + new_x_range / 2)  # 设置新的 x 轴范围

    def zoom(self, event):  # 定义缩放方法
        base_scale = 1.1  # 缩放基础比例
        scale_factor = 1 / base_scale if event.button == 'up' else base_scale  # 计算缩放因子

        xdata = event.xdata  # 获取事件的 x 数据
        ydata = event.ydata  # 获取事件的 y 数据
        if xdata is None or ydata is None:  # 若数据为空,则返回
            return

        xlim = self.ax1.get_xlim()  # 获取 x 轴范围
        ylim = self.ax1.get_ylim()  # 获取 y 轴范围
        x_range = (xlim[1] - xlim[0]) * scale_factor  # 计算新的 x 轴范围
        y_range = (ylim[1] - ylim[0]) * scale_factor  # 计算新的 y 轴范围

        x_center = (xlim[0] + xlim[1]) / 2  # 计算 x 轴中心
        y_center = (ylim[0] + ylim[1]) / 2  # 计算 y 轴中心

        # 设置新的 x 和 y 轴范围
        self.ax1.set_xlim([x_center - x_range / 2, x_center + x_range / 2])
        self.ax1.set_ylim([y_center - y_range / 2, y_center + y_range / 2])
        self.adjust_axes()  # 调整坐标轴范围
        self.canvas1.draw_idle()  # 重新绘制图表

    def on_press(self, event):  # 定义鼠标按下事件处理方法
        if event.button == 1:  # 若为左键按下
            self.dragging = True  # 设置拖动标志为 True
            self.last_mouse_pos = (event.x, event.y)  # 记录当前鼠标位置

    def on_release(self, event):  # 定义鼠标释放事件处理方法
        if event.button == 1:  # 若为左键释放
            self.dragging = False  # 设置拖动标志为 False
            self.last_mouse_pos = None  # 清空鼠标位置

    def on_motion(self, event):  # 定义鼠标移动事件处理方法
        if self.dragging and event.xdata is not None and event.ydata is not None:  # 若正在拖动且鼠标位置有效
            dx = event.x - self.last_mouse_pos[0]  # 计算 x 方向位移
            dy = event.y - self.last_mouse_pos[1]  # 计算 y 方向位移

            xlim = self.ax1.get_xlim()  # 获取 x 轴范围
            ylim = self.ax1.get_ylim()  # 获取 y 轴范围
            width, height = self.canvas1.get_width_height()  # 获取画布宽度和高度
            dx_data = dx * (xlim[1] - xlim[0]) / width  # 计算 x 方向的数据位移
            dy_data = dy * (ylim[1] - ylim[0]) / height  # 计算 y 方向的数据位移

            # 更新 x 和 y 轴范围
            self.ax1.set_xlim(xlim[0] - dx_data, xlim[1] - dx_data)
            self.ax1.set_ylim(ylim[0] - dy_data, ylim[1] - dy_data)
            self.last_mouse_pos = (event.x, event.y)  # 更新鼠标位置
            self.adjust_axes()  # 调整坐标轴范围
            self.canvas1.draw_idle()  # 重新绘制图表

    # 输入值变化重置按钮状态和图像
    def reset_button_and_image(self):
        # 禁用按钮
        self.iterate_button.setEnabled(False)
        self.show_result_button.setEnabled(False)
        # 重置界面
        self.figure1.clear()
        self.canvas1.draw()
        self.figure2.clear()
        self.canvas2.draw()
        # 清空结果显示框
        self.iteration_result_text.clear()
        # 重置迭代次数
        self.count = 1

    def start_plot_function(self):
        # 参数校验
        if not self.valid_param():
            return
        # 启用按钮
        self.iterate_button.setEnabled(True)
        self.show_result_button.setEnabled(True)
        # 定义变量
        x = Symbol('x')
        # 定义函数
        self.f_expr = eval(self.function_entry.text())
        self.f = lambdify(x, self.f_expr)
        # 求一阶导数
        self.df_expr = diff(self.f_expr, x)
        self.df = lambdify(x, self.df_expr)
        # 清除第一个绘图区域
        self.figure1.clear()
        self.ax1 = self.figure1.add_subplot(111)
        x_range_extension = 1  # 可以调整 x 轴范围
        X = np.linspace(float(self.initial_guess_entry.text()) - x_range_extension,
                        float(self.initial_guess_entry.text()) + x_range_extension, 1000000)
        self.ax1.set_title('函数表达式参考图像')  # 添加标题
        # 绘制函数图像
        self.ax1.plot(X, self.f(X), 'green', label="函数表达式")
        # 在图表上绘制函数图像和辅助线
        self.ax1.axhline(0, color='black', linestyle="--", linewidth=0.5)
        self.ax1.axvline(0, color='black', linestyle="--", linewidth=0.5)
        self.ax1.legend()
        self.ax1.grid(True)
        # 刷新第一个绘图区域
        self.canvas1.draw()
        self.result, self.num, self.All = self.Newton(float(self.initial_guess_entry.text()),
                                                      float(self.error_entry.text()), int(self.max_entry.text()))
        # 标明迭代次数
        self.count = 1

    def reset_option(self):
        # 重置所有输入框
        self.function_entry.clear()
        self.initial_guess_entry.clear()
        self.error_entry.clear()
        self.precision_entry.clear()
        self.max_entry.clear()
        # 禁用按钮
        self.iterate_button.setEnabled(False)
        self.show_result_button.setEnabled(False)
        # 清空图形区域
        self.figure1.clear()
        self.canvas1.draw()
        self.figure2.clear()
        self.canvas2.draw()
        # 清空结果显示框
        self.iteration_result_text.clear()
        # 重置迭代次数
        self.count = 1

    # 牛顿法(输入三个参数,初始猜值、误差、最大迭代次数)
    def Newton(self, x0, E, max_count=100):
        ans_list = [x0]  # 存放迭代过程中的所有解
        for i in range(max_count):  # 最大迭代次数
            ans_list.append(ans_list[i] - self.f(ans_list[i]) / self.df(ans_list[i]))  # 迭代公式
            if abs(ans_list[i + 1] - ans_list[i]) <= E:
                break
        # 返回最终迭代结果,迭代次数,迭代过程全解
        return ans_list[i + 1], i + 1, ans_list

    def plot_iteration(self, show_all):
        # 判断类型
        if show_all:
            data = self.All
            self.count = 1
        else:
            if self.count == len(self.All) + 1:
                self.show_error("已结束", "迭代次数已达到最大值")
                return
            data = self.All[:self.count]
            self.count += 1
        # 清除第二个绘图区域
        self.figure2.clear()
        ax2 = self.figure2.add_subplot(111)
        ax2.set_title('迭代值变化图像')  # 添加标题
        # 绘制迭代过程图像
        self.update_result(data)
        ax2.plot(np.arange(0, len(data), 1), data, '#bcbd22', linestyle='-',
                 label="迭代过程", marker='o', markersize=6,
                 markeredgecolor='black', markerfacecolor='red')
        ax2.set_ylabel('迭代数值')
        ax2.set_xlabel('迭代次数')
        # 在每个点上添加数值
        for i, txt in enumerate(data):
            ax2.text(i, txt, f'{txt:.{self.precision_entry.text()}f}', fontsize=8, verticalalignment='bottom',
                     horizontalalignment='right')
        ax2.legend()
        ax2.grid(True)
        # 刷新第二个绘图区域
        self.canvas2.draw()

        # 绘制迭代过程图像
        for x_current in data:  # 进行迭代
            y_current = self.f(x_current)  # 计算当前点的函数值
            y_prime_current = self.df(x_current)  # 计算当前点的导数值
            x_next = x_current - y_current / y_prime_current  # 计算下一个点的位置
            # 在图表上绘制迭代过程中的点和连线
            self.ax1.plot([x_current, x_next], [y_current, 0], 'ro-')
            self.ax1.plot([x_next, x_next], [0, self.f(x_next)], 'g--')
        self.canvas1.draw()  # 重新绘制图表

    def update_result(self, temp):
        # 更新迭代结果文本框内容
        self.iteration_result_text.clear()
        self.iteration_result_text.append(f"迭代过程:")

        for i, val in enumerate(temp):
            if i == 0:
                self.iteration_result_text.append(f"初始猜测值:x = {val:.{self.precision_entry.text()}f}")
            else:
                self.iteration_result_text.append(f"第{i}次迭代:x = {val:.{self.precision_entry.text()}f}")
            if i == self.num:
                self.iteration_result_text.append(
                    f"======\n迭代结束:\n方程的一个实根为x = {val:.{self.precision_entry.text()}f} \n迭代次数: {self.num}")

    def show_help(self):
        help_message = (
            "欢迎使用一元方程求根中牛顿迭代法的分析程序!\n\n"
            "以下是每个输入框和按钮的作用以及输入函数的格式要求:\n\n"
            "- 函数表达式输入框:\n"
            "  请输入一个数学函数表达式,例如:x**2 + 3*x - 5、exp(x) + 10*x - 2。\n"
            "  表达式应当符合python语法,如加法(+), 减法(-), 乘法(*), 除法(/), 幂(**)。 \n"
            "  特殊函数输入格式请参考SymPy官方文档,例如e^x => exp(x)\n"
            "  SymPy官方文档:https://docs.sympy.org/latest/tutorials/intro-tutorial/index.html#intro-tutorial\n"
            "  Python语法学习:https://blog.csdn.net/m0_66570338/article/details/128714062\n\n"
            "- 初始猜测值输入框:\n"
            "  输入一个初始猜测值,作为迭代计算的起始点。\n"
            "  可以输入整数或小数。\n\n"
            "- 误差输入框:\n"
            "  输入一个用于判断迭代精度的误差值。\n"
            "  当迭代结果与上一次迭代结果的差值小于误差时,迭代停止。\n\n"
            "- 显示精度位输入框:\n"
            "  设置迭代过程中结果的显示精度位数。\n"
            "  输入一个正整数,表示显示结果的小数位数。\n\n"
            "- 最大迭代次数输入框:\n"
            "  设置最大迭代次数,以避免迭代无限循环。\n"
            "  输入一个正整数,表示最大的迭代次数。\n\n"
            "- 绘制函数按钮:\n"
            "  根据输入的函数表达式,绘制函数图像。\n\n"
            "- 逐步迭代按钮:\n"
            "  逐步展示迭代过程的图像,并显示每次迭代的结果。\n\n"
            "- 一键迭代按钮:\n"
            "  一次性展示所有迭代过程的图像,并显示最终的迭代结果。\n\n"
            "- 重置程序按钮:\n"
            "  重置所有的操作记录,清空输入框和图像区域,恢复到初始状态。\n"
        )
        QMessageBox.information(self, "使用帮助", help_message, QMessageBox.Ok)

    def valid_param(self):
        # # 参数校验
        function_entry = self.function_entry.text()
        initial_guess_entry = self.initial_guess_entry.text()
        error_entry = self.error_entry.text()
        precision_entry = self.precision_entry.text()
        max_entry = self.max_entry.text()
        # 检查函数表达式
        if not self.function_entry.text():
            self.show_error("错误", "函数表达式输入有误,请仔细检查或参考帮助文档")
            return False
        else:
            try:
                x = Symbol('x')
                lambdify(x, eval(function_entry))
            except Exception as e:
                self.show_error("错误", "函数表达式输入有误,请仔细检查或参考帮助文档")
                print(e)
                return False
        # 检查初始猜测值
        if not initial_guess_entry:
            self.show_error("错误", "初始猜测值输入有误,请仔细检查或参考帮助文档")
            return False
        elif not initial_guess_entry.replace('.', '', 1).isdigit():
            self.show_error("错误", "初始猜测值输入有误,必须为小数或整数")
            return False
        # 检查误差
        if not error_entry:
            self.show_error("错误", "误差输入有误,请仔细检查")
            return False
        elif not error_entry.replace('.', '', 1).isdigit():
            self.show_error("错误", "误差输入有误,必须为小数或整数")
            return False
        # 检查迭代精度
        if not precision_entry:
            self.show_error("错误", "显示精度位输入有误,请仔细检查")
            return False
        elif not precision_entry.isdigit():
            self.show_error("错误", "显示精度位输入有误,必须为整数")
            return False
        elif int(precision_entry) <= 0:
            self.show_error("错误", "显示精度位输入有误,必须大于0")
            return False
        # 检查最大迭代次数
        if not max_entry:
            self.show_error("错误", "最大迭代次数输入有误,请仔细检查")
            return False
        elif not max_entry.isdigit():
            self.show_error("错误", "最大迭代次数输入有误,必须为整数")
            return False
        elif int(max_entry) <= 0:
            self.show_error("错误", "迭代精度位输入有误,必须大于0")
            return False
        return True

    def show_error(self, title, message):
        QMessageBox.critical(self, title, message, QMessageBox.Ok)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = FunctionPlotterApp()
    window.show()
    sys.exit(app.exec_())

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1818642.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

罗森伯格1800M 2000M 2400M 900M无源互调分析仪

在无线通信领域&#xff0c;频段是宝贵的资源&#xff0c;不同的通信系统通常会采用不同的频段以满足其传输需求。随着技术的发展&#xff0c;越来越多的通信系统被部署在各种频段上。为了准确、高效地测试和调试这些 信系统&#xff0c;各种测试设备也应运而生。源互调分析仪便…

rizhuti1.9-最新版-推荐文章缩略图

下载地址&#xff1a;rizhuti1.9-最新版-推荐文章缩略图 商城功能后台可以一键开启关闭&#xff0c;关闭后就是一个布局灵活&#xff0c;界面优美&#xff0c;速度超快的wordpress博客主题

2024新版AI创作系统pro搭建,支持文生漫画视频ai对话问答/ai音乐创作/ai测评/ai换脸/ai写真

一、系统介绍 一款结合了多种功能应用&#xff0c;是当前市场最热门的AI工具综合体 AI动漫生成 AI音乐创作 AI写真 AI换脸 AI绘画 AI趣测 六大AI功能 AI创作小程序是一种利用人工智能技术为用户提供服务&#xff0c;并通过某种方式实现的小程序。这种小程序可以应用于多…

微服务 | Springboot整合Dubbo+Nacos实现RPC调用

官网&#xff1a;Apache Dubbo 随着互联网技术的飞速发展&#xff0c;越来越多的企业和开发者开始关注微服务架构。微服务架构可以将一个大型的应用拆分成多个独立、可扩展、可维护的小型服务&#xff0c;每个服务负责实现应用的一部分功能。这种架构方式可以提高开发效率&…

RK3568技术笔记 Ubuntu 安装VMware Tools

安装 VMware Tools 后可以直接使用复制粘贴功能拷贝 Ubuntu 系统和 windows 主机内的文件&#xff0c;非常方便。 开启虚拟机&#xff0c;必须要进入ubuntu系统后才能进行下面的步骤。 单击 VMware 软件中的标签“虚拟机”&#xff0c;在下拉的菜单中单击“安装VMware Tools &…

x64-linux下在vscode使用vcpkg

1.使用vscode远程连接上对应的linux &#xff0c;或者直接在图形化界面上使用。 2.安装vcpkg 插件&#xff0c;然后打开插件设置。 注意&#xff1a;defalut和host的主机一定和你自己的主机一致&#xff0c;且必须符合vcpkg三元组格式&#xff0c;其中你可以选择工作台的设置&a…

R语言ggHoriPlot包绘制地平线图

数据和代码获取&#xff1a;请查看主页个人信息&#xff01;&#xff01;&#xff01; 关键词“地平线图” 1. 数据读取与处理 首先&#xff0c;从TSV文件中读取数据&#xff0c;并进行数据清洗和处理。 rm(listls()) pacman::p_load(tidyverse,ggalt,ggHoriPlot,hrbrthemes…

ACM MM2024 Rebuttal Latex模板如何去掉标题

声明 Latex初学者&#xff0c;非官方指定做法&#xff0c;仅供大家参考 问题 ACM MM 2024会议&#xff0c;官方给定的Rebuttal latex模板&#xff0c;title占据了两行&#xff0c;但又限制Rebuttal只能有一页&#xff0c;所以在微信群里&#xff0c;大家希望能将这个title删…

springboot 整合redis问题,缓存击穿,穿透,雪崩,分布式锁

boot整合redis 压力测试出现失败 解决方案 排除lettuce 使用jedis <!-- 引入redis --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId><exclusions><exclus…

快来!AI绘画Stable Diffusion 3终于开源了,更强的文字渲染和理解力,12G显卡可跑!

大家好&#xff0c;我是设计师阿威 Stable Diffusion 3终于开源了&#xff0c;2B参数的Stable Diffusion 3 Medium模型已经可以在HuggingFace上下载了&#xff01;如无法科学上网的小伙伴我也准备好了网盘资料&#xff0c;请看文末扫描获取哦&#xff01; Stable Diffusion 3 …

力扣每日一题-419

题目 给你一个大小为 m x n 的矩阵 board 表示甲板&#xff0c;其中&#xff0c;每个单元格可以是一艘战舰 X 或者是一个空位 . &#xff0c;返回在甲板 board 上放置的 战舰 的数量。 战舰 只能水平或者垂直放置在 board 上。换句话说&#xff0c;战舰只能按 1 x k&#xff…

C++中stack和queue

前言 在 C 中&#xff0c;stack&#xff08;栈&#xff09;和 queue&#xff08;队列&#xff09;是两种常用的容器适配器&#xff0c;分别用于管理数据的后进先出&#xff08;LIFO&#xff09;和先进先出&#xff08;FIFO&#xff09;访问模式。本文将详细介绍这两种数据结构的…

一文彻底理解机器学习 ROC-AUC 指标

在机器学习和数据科学的江湖中&#xff0c;评估模型的好坏是非常关键的一环。而 ROC&#xff08;Receiver Operating Characteristic&#xff09;曲线和 AUC&#xff08;Area Under Curve&#xff09;正是评估分类模型性能的重要工具。 这个知识点在面试中也很频繁的出现。尽管…

如何将接口返回/n替换为react.js中的换行符

将每个/n替换为ReactJS中的一个<br>标记。cpa_ability为后端返回的字段名

技术流 | ClickHouse工具ckman v3.1.3 sinker v3.1.8 版本发布

【本文作者&#xff1a;擎创科技 ClickHouse专家&#xff0c;ckman作者禹鼎侯】 在这个端午小长假里&#xff0c;ckman和clickhouse_sinker分别带来了全新的版本。让我们一起来看看&#xff0c;新版本都有哪些新特性吧&#xff01; ckman v3.1.3新版本特性 ckman v3.1.3作为…

【全开源】多功能投票小程序系统源码(ThinkPHP+FastAdmin+Uniapp)

&#x1f680; 多功能投票小程序&#xff0c;让决策变得更简单&#xff01; 基于ThinkPHPFastAdminUniapp开发的多功能系统&#xff0c;支持图文投票、自定义选手报名内容、自定义主题色、礼物功能(高级授权)、弹幕功能(高级授权)、会员发布、支持数据库私有化部署&#xff0c…

19_axios入门到进阶

文章目录 [toc] 1. Axios概念1.1 普通函数&&回调函数 2. Promise概念3. Promise基本使用方法3. Promise创造的异步函数如果直接return&#xff0c;默认是resolved状态4.Promise关键字async&&await5.Axios异步处理方案5.1 案例请求&#xff1a;请求后太获取随机…

Spring Cloud Stream 消息驱动基础入门与实践总结

Spring Cloud Stream是用于构建与共享消息传递系统连接的高度可伸缩的事件驱动微服务框架&#xff0c;该框架提供了一个灵活的编程模型&#xff0c;它建立在已经建立和熟悉的Spring熟语和最佳实践上&#xff0c;包括支持持久化的发布/订阅、消费组以及消息分区这三个核心概念。…

【OceanBase诊断调优】 —— DDL时报磁盘不足问题排查

1. 背景 由于在4.x的部分版本中&#xff0c;我们对于一些ddl操作还存在磁盘空间放大问题&#xff0c;本文主要介绍了这一类问题的排查。 2. 问题排查 2.1 整体排查链路 2.2 问题现象 DDL过程中报磁盘空间不足&#xff0c;需要确认是否符合预期&#xff0c;如果是符合预期&a…

Java使用swing实现简易计算器

效果如下 代码实现 import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener;public class SimpleCalculator {private JFrame frame;private JTextField numField1;private JTextField numField2;private JTex…