解非线性方程的两种方法与python实现

写在开头: 非线性方程,就是因变量与自变量之间的关系不是线性的关系,这类方程很多,例如平方关系、对数关系、指数关系、三角函数关系等等。求解此类方程往往很难得到精确解,经常需要求近似解问题。本文将从一道数列题开始,引出一种求解非线性方程的基础方法:简单迭代法。然后讲解科学计算器的求解方法:牛顿切线法。最后会用python实现两种方法并可视化。


不动点迭代法

引子

先来看一道简单的数列题。

已知数列 a n 的递推公式 a n + 1 = 1 a n + 1 , 且 a 1 = 1 , 求 lim ⁡ x → ∞ a n 已知数列a_{n}的递推公式a_{n+1}=\frac{1}{a_{n}+1} ,且a_{1}=1,求\lim_{x \to \infty}a_{n} 已知数列an的递推公式an+1=an+11,a1=1,xliman

解此题只需令 lim ⁡ x → ∞ a n = A , 解方程 A = 1 A + 1 \lim_{x \to \infty}a_{n} =A,解方程A=\frac{1}{A+1} limxan=A,解方程A=A+11即可。但借助科学计算器还有一种投机取巧的方法:利用递推公式不断求 a n a_{n} an。当n足够大时, a n ( 如 a 100 ) a_{n}(如a_{100}) an(a100)即可近似为 a n a_{n} an的极限。而这一过程借助科学计算器的“Ans”功能可以很方便地实现。

可以发现:我们用这种方法绕开了二次方程的求根公式解出了方程 x = 1 x + 1 x=\frac{1}{x+1} x=x+11的一个实数数值解。那么对于任意形如 x = g ( x ) x=g(x) x=g(x)的方程,是不是也可以用构造数列 a n + 1 = g ( a n ) a_{n+1}=g(a_{n}) an+1=g(an)来求解呢?这就是不动点迭代法了。

具体操作

不动点迭代又称为简单迭代,用以求解方程 f ( x ) = 0 f(x)=0 f(x)=0。方法如下:

  1. 方程转换为 x = g ( x ) x=g(x) x=g(x)
  2. x 0 x_{0} x0设定一个初值
  3. x i + 1 = g ( x i ) x_{i+1}=g(x_{i}) xi+1=g(xi)
  4. 若满足结束条件(i大于某个预设的值,或 ∣ x i + 1 − x i ∣ |x_{i+1}-x_{i}| xi+1xi小于某个预设的值) x i + 1 x_{i+1} xi+1为解,否则返回第3步

这里将方程 f ( x ) = 0 f(x)=0 f(x)=0转换为 x = g ( x ) x=g(x) x=g(x)是很容易的,比如对于 f ( x ) = x − c o s ( x ) f(x)=x-cos(x) f(x)=xcos(x),求解 f ( x ) = 0 f(x)=0 f(x)=0即为求解 x − c o s ( x ) = 0 x-cos(x)=0 xcos(x)=0,即 x = c o s ( x ) x=cos(x) x=cos(x),因此 g ( x ) = c o s ( x ) g(x)=cos(x) g(x)=cos(x);但是需要注意转换方法不唯一,这可能会影响计算结果。

缺点

  • 只能求一个解
  • 函数 φ ( x ) 在区间 [ a , b ] 内 \varphi(x)在区间[a,b]内 φ(x)在区间[a,b]必须满足以下的收敛条件:
    1. 有一阶导数
    2. 对任意 x ∈ [ a , b ] x\in[a,b] x[a,b],总存有 φ ( x ) ∈ [ a , b ] \varphi(x)\in[a,b] φ(x)[a,b]
    3. 对任意 x ∈ [ a , b ] x\in[a,b] x[a,b],总存有0<L<1,使得 ∣ φ ( x ) ′ ∣ ≤ L < 1 |{\varphi(x)}'|\le L<1 φ(x)L<1
  • 为满足收敛条件,需要选取适当初始值

牛顿切线法

鉴于不动点迭代法有时无法满足的收敛条件,科学计算器在求解非线性方程时会运用另一种方法–牛顿切线法,又称牛顿法。
牛顿切线法也是一种迭代法。它的操作很简单,首先通过移项把方程转化成求函数 f ( x ) f(x) f(x)的零点的问题。在给定一个迭代点 x i x_{i} xi时,作 f ( x ) f(x) f(x) x i x_{i} xi的切线 y − f ( x i ) = f ′ ( x i ) ( x − x i ) y-f(x_{i})=f'(x_{i})(x-x_{i}) yf(xi)=f(xi)(xxi) x i + 1 x_{i+1} xi+1为切线与x轴的交点 x i − f ( x i ) f ′ ( x i ) x_{i}-\frac{f(x_{i})}{f'(x_{i})} xif(xi)f(xi)。与不动点迭代法一样,在满足结束条件时终止迭代。

如何理解这种操作呢?可以把 f ( x ) f(x) f(x)的切线看作 f ( x ) f(x) f(x) x i x_{i} xi的一阶泰勒近似,既然函数的切线与函数是相似的,他们的零点也是相近的。那就把切线的零点当做目标值的近似。

接下来是一个例子,所求方程为 0.1 x 2 − x − 3 = 0 , x 0 = 1 0.1x^2-x-3=0,x_{0}=1 0.1x2x3=0,x0=1,共迭代了两次。
在这里插入图片描述

可以看到,迭代两次后的 x 2 x_{2} x2已经相当接近 x t a r g e t x_{target} xtarget了。

一般我们希望x尽可能接近理论值 x t a r g e t x_{target} xtarget,但是有时确切的理论值是未知的,所以也可以令 ∣ y ∣ |y| y尽可能小。现在我们知道了在使用卡西欧计算器时,可以使用L-R的功能来估算 ∣ y ∣ |y| y(即误差)。而输入x的功能是为了设置迭代的初始点。
在这里插入图片描述
在这里插入图片描述

除了求解方程,牛顿法还有更广泛的应用。在已知某函数的导数时,可以令导数为零,解方程得函数的极值。将一元函数推广到多元函数,用向量,梯度,Heese矩阵替换自变量,导数,二阶导数,就可以把牛顿法用于多维无约束最优化问题。


python实现

调用了numpy库与matplotlib库。使用同一个函数接口solve实现牛顿法与不动点迭代法,作为示例的方程为 a r c t a n ( x − 7 ) − 0.3 x = 0 arctan(x-7)-0.3x=0 arctan(x7)0.3x=0。在以迭代次数作为结束条件的基础上,这里增加了一种终止迭代的条件:两次x的差值 ∣ x i + 1 − x i ∣ |x_{i+1}-x_{i}| xi+1xi小于某个预设的值 d e l t a delta delta

由于牛顿法涉及导数运算,我们用数值微分公式 f ′ ( x ) ≈ f ( x + h ) − f ( x − h ) 2 h f'(x)≈\frac{f(x+h)-f(x-h)}{2h} f(x)2hf(x+h)f(xh)近似导数,由二阶泰勒展开公式可推得其误差为 O ( h 2 ) O(h^2) O(h2)

主要函数与大致流程:

  • 输入:在func函数中输入需要为零的函数,即方程 f ( x ) = 0 f(x)=0 f(x)=0中的 f ( x ) f(x) f(x),在solve函数中输入初始迭代点 x 0 x_{0} x0,迭代次数上限iteration(默认100),终止迭代的误差delta(默认1e-5)。
  • 输出:牛顿法与不动点迭代法各自的解,和两张图ax[0],ax[1]
  • 函数func():表示 f ( x ) f(x) f(x)
  • 函数derivate():对func使用数值微分求导
  • 函数solve():绘制ax[0]的一组迭代点与ax[1]的一条折线
  • 子图ax[0]:函数图像与迭代点
  • 子图ax[1]: f ( x ) f(x) f(x)随迭代次数变化的曲线,若能有效求解,曲线将收敛与0
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号

def func(x):#需要为0的函数
    y=np.arctan(x-7)-0.3*x#自定义要求解的函数
    return y
def derivate(x):#数值微分求导,h取1e-6
    return (func(x+1e-6)-func(x-1e-6))/2e-6
def solve(x,iteration=100,delta=1e-5,method='fixed_point'):#绘制迭代点和下降曲线
    doty=[func(x)]#保存迭代点的纵坐标,用来绘制折线图,先记录初始点
    n=1#记录迭代次数
    for i in range(iteration):
        if(method=='fixed_point'):#不动点迭代
            xnext=func(x)+x
            colors="blue"
        if(method=='newton'):#牛顿迭代
            xnext=x-func(x)/derivate(x)
            colors="orange"
        ax[0].scatter(xnext,func(xnext),marker='o',s=10,color=colors,alpha=1,zorder=3)
        doty.append(func(xnext))#添加迭代点的纵坐标
        n=n+1
        if(abs(x-xnext)<delta):#新增的终止条件
            break
        x=xnext
    ax[1].plot(np.arange(0,n),doty,'o-',markersize=3)#绘制函数值下降曲线
    return x;

#画布的基础设置
X=np.linspace(-15,20,500)  # X轴坐标数据
Y =func(X)               # Y轴坐标数据
fig, ax = plt.subplots(1, 2, figsize=(10, 4),dpi=120)#创建画布
ax[0].tick_params(labelsize=12)#坐标字号
ax[1].tick_params(labelsize=12)
ax[0].set_xlabel('$x$')#坐标名称
ax[0].set_ylabel('$y$')
ax[1].set_xlabel('迭代次数')
ax[1].set_ylabel('函数值')
ax[0].grid()#增加网格
ax[1].grid()

ax[0].plot(X,0*X,color="black",linewidth=1,zorder=1)#作图y=0
ax[0].plot(X,Y,label="$f(x)$",color="black",linewidth=1,zorder=2)#作出函数图像

#绘制两种方法的迭代点与函数下降曲线
ax[0].scatter(8,func(8),color="red",s=10,label="初始点")#绘制初始点
ans1=solve(8,100,method='fixed_point')
ans2=solve(8,100,method='newton')
ax[0].legend(fontsize=8)#设置图例
ax[1].legend(['不动点迭代法','牛顿法'],fontsize=8)

print('不动点迭代法的结果:'+str(ans1))
print('牛顿法的结果:'+str(ans2))

plt.show()

结果如下
在这里插入图片描述

  • 1
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
非线性方程组是指方程中至少包含一个非线性项的方程组。而二分法是一种常用的数值求解非线性方程方法之一。 在Python中使用二分法求解非线性方程组的步骤如下: 1. 定义非线性方程组:根据题目给定的非线性方程组,首先将方程组表示成函数的形式。例如,假设方程组为f(x)=0,则需要定义函数f(x)。 2. 确定求解的范围:根据函数的特性选择一个合适的求解范围。二分法要求在求解范围内存在一个根。 3. 实现二分法函数:编写一个二分法函数,根据给定的非线性方程组函数和求解范围,使用二分法迭代求解方程组。 - 使用两个指针low和high表示求解范围的左右边界。 - 根据二分法的思想,通过计算中点mid=(low+high)/2,将求解范围划分为两半。 - 计算函数f(mid)的值,并判断其与0的关系,若小于0则更新low为mid,若大于0则更新high为mid。 - 不断重复上述步骤,直到求解精度满足要求或迭代次数达到指定阈值。 4. 调用二分法函数求解:在主程序中调用定义好的二分法函数,传入非线性方程组函数和求解范围等参数。根据需要可以设置求解精度和迭代次数阈值。 5. 输出结果:根据需要输出方程组的根或最优,并进行结果的验证和分析。 总体而言,使用Python的二分法求解非线性方程组的方法相对简单直观。但需要注意的是,二分法只能求得一个根,如果存在多个根或非线性方程组无,需要使用其他数值方法进行求解
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值