MATLAB和Python求解非线性方程组

解非线性方程

考虑以下形式的非线性方程:

f ( x ) = 0 \boldsymbol{f}\left( \boldsymbol{x} \right) =0 f(x)=0

其中 f : R → R \boldsymbol{f}:\mathbb{R}\rightarrow \mathbb{R} f:RR是非线性函数。 问题是找到一个点 x = x ∗ \boldsymbol{x}=\boldsymbol{x}^* x=x使得 f ( x ∗ ) = 0 \boldsymbol{f}\left( \boldsymbol{x}^* \right) =0 f(x)=0。然后, x = x ∗ \boldsymbol{x}=\boldsymbol{x}^* x=x被称为函数 f f f的根。 例如,如果 f ( x ) = e − x − cos ⁡ x + 0.5 \boldsymbol{f}\left( \boldsymbol{x} \right) =\boldsymbol{e}^{-\boldsymbol{x}}-\cos \boldsymbol{x}+0.5 f(x)=excosx+0.5,则 f ( x ) = e − x − cos ⁡ x + 0.5 = 0 \boldsymbol{f}\left( \boldsymbol{x} \right) =\boldsymbol{e}^{-\boldsymbol{x}}-\cos \boldsymbol{x}+0.5=0 f(x)=excosx+0.5=0的根位于曲线 e − x + 0.5 \boldsymbol{e}^{-\boldsymbol{x}}+0.5 ex+0.5 cos ⁡ ( x ) \cos \left( \boldsymbol{x} \right) cos(x) 的交点 如xia图4.1所示。

在本中,将讨论四种求解给定非线性方程的方法,即二分法,牛顿-拉夫森法,割线和迭代法,并在MATLAB和Python中实现。

二等分法

假设函数 f ( x ) \boldsymbol{f}\left( \boldsymbol{x} \right) f(x) 在间隔 [ a , b ] \left[ \boldsymbol{a},\boldsymbol{b} \right] [a,b] 中是连续的,并且随着函数从a移至b,其符号从正变为负,反之亦然。 中间值定理的直接结果是,连续函数无法在不经过零的情况下在一个间隔内改变其符号。

二等分方法是一种迭代方法,该方法在每次迭代中将包含根的间隔分为两个相等的子间隔,将不包含根的一半除去,然后在另一半中寻找根。

如果间隔 [ a , b ] \left[ \boldsymbol{a},\boldsymbol{b} \right] [a,b] 分为两个相等的子间隔 [ a , c ] \left[ \boldsymbol{a},\boldsymbol{c} \right] [a,c] [ c , b ] \left[ \boldsymbol{c},\boldsymbol{b} \right] [c,b] ,其中 c = ( a + b ) / 2 \boldsymbol{c}=\left( \boldsymbol{a}+\boldsymbol{b} \right) /2 c=(a+b)/2是间隔 [ a , b ] \left[ \boldsymbol{a},\boldsymbol{b} \right] [a,b] 的中点。函数 f f f的根在 [ a , c ] \left[ \boldsymbol{a},\boldsymbol{c} \right] [a,c] [ c , b ] \left[ \boldsymbol{c},\boldsymbol{b} \right] [c,b] 中。 如果它位于 [ a , c ] \left[ \boldsymbol{a},\boldsymbol{c} \right] [a,c] 中,则 f ( a ) ⋅ f ( c ) < 0 \boldsymbol{f}\left( \boldsymbol{a} \right) \cdot \boldsymbol{f}\left( \boldsymbol{c} \right) <0 f(a)f(c)<0。在这种情况下,我们知道根不在 [ a , c ] \left[ \boldsymbol{a},\boldsymbol{c} \right] [a,c] 区间内,因此我们在 [ c , b ] \left[ \boldsymbol{c},\boldsymbol{b} \right] [c,b] 中寻找它 ,二等分法继续将包含根的间隔分为两个子间隔,这样一个子间隔包含根,而另一个不包含根。 因此,该方法仅考虑包含根的间隔并丢弃不包含。

实现二分法的MATLAB代码部分如下,

 function x = Bisection(f, a, b, Epsilon)
	 while b-a ≥ Epsilon
		 c = (a+b)/2 ;
		 if f(a)*f(c) < 0
			 b = c ;
		 elseif f(b)*f(c) < 0
			 a = c ;
		 else
			 x = c ;
		 end
	end
	x=c ;

现在,我们可以从命令提示符处调用函数二分法,

>> format long
>> Epsilon = 1e-8 ;
>> f = @(x) xˆ2 - 3 ;
>> r = Bisection(f, 1, 2, Epsilon)
r =
1.732050813734531
>> s = Bisection(f, -2, -1, Epsilon)
s =
-1

实现二分法的Python代码部分如下,


In [1]: f = lambda x: x**2 - 3
In [2]: a, b = 1., 2.
In [3]: Eps = 1e-8
In [4]: x, Iters = Bisection(f, a, b, Eps)
In [5]: print(’Approximate root is:, x, ’\nIterations:, Iters)
Approximate root is: 1.7320508062839508
Iterations: 25

牛顿-拉普森法

如果函数 f ( x ) \boldsymbol{f}\left( \boldsymbol{x} \right) f(x) 在点 x 0 \boldsymbol{x}_0 x0附近是连续的,则可以用以下形式编写:

f ( x ) = f ( x 0 ) + f ′ ( x 0 ) ( x − x 0 ) + O ( ( x − x 0 ) 2 ) \boldsymbol{f}\left( \boldsymbol{x} \right) =\boldsymbol{f}\left( \boldsymbol{x}_0 \right) +\boldsymbol{f}^{\prime}\left( \boldsymbol{x}_0 \right) \left( \boldsymbol{x}-\boldsymbol{x}_0 \right) +\mathcal{O}\left( \left( \boldsymbol{x}-\boldsymbol{x}_0 \right) ^2 \right) f(x)=f(x0)+f(x0)(xx0)+O((xx0)2)

现在,如果 x 1 \boldsymbol{x}_1 x1是函数 f ( x ) \boldsymbol{f}\left( \boldsymbol{x} \right) f(x) 的根,则 f ( x 1 ) = 0 \boldsymbol{f}\left( \boldsymbol{x}_1 \right) =0 f(x1)=0。即:

f ( x 0 ) + f ′ ( x 0 ) ( x − x 0 ) ≈ f ( x 1 ) = 0 \boldsymbol{f}\left( \boldsymbol{x}_0 \right) +\boldsymbol{f}^{\prime}\left( \boldsymbol{x}_0 \right) \left( \boldsymbol{x}-\boldsymbol{x}_0 \right) \approx \boldsymbol{f}\left( \boldsymbol{x}_1 \right) =0 f(x0)+f(x0)(xx0)f(x1)=0

根据以上公式:

x 1 = x 0 − f ( x n ) f ′ ( x 0 ) \boldsymbol{x}_1=\boldsymbol{x}_0-\frac{\boldsymbol{f}\left( \boldsymbol{x}_{\boldsymbol{n}} \right)}{\boldsymbol{f}^{\prime}\left( \boldsymbol{x}_0 \right)} x1=x0f(x0)f(xn)

假设 f ′ ( x 0 ) ≠ 0 \boldsymbol{f}^{\prime}\left( \boldsymbol{x}_0 \right) \ne 0 f(x0)=0

牛顿-拉夫森法是一种迭代方法,用于找到最接近函数 f ( x ) \boldsymbol{f}\left( \boldsymbol{x} \right) f(x) 到初始猜测值 x 0 x_0 x0的近似值。 从 x 0 x_0 x0开始,它会生成一个数字序列 x 0 , x 1 , x 2 , ⋯   , \boldsymbol{x}_0,\boldsymbol{x}_1,\boldsymbol{x}_2,\cdots , x0,x1,x2,,其中,

x n + 1 = x n − f ( x n ) f ′ ( x n ) \boldsymbol{x}_{\boldsymbol{n}+1}=\boldsymbol{x}_{\boldsymbol{n}}-\frac{\boldsymbol{f}\left( \boldsymbol{x}_{\boldsymbol{n}} \right)}{\boldsymbol{f}^{\prime}\left( \boldsymbol{x}_{\boldsymbol{n}} \right)} xn+1=xnf(xn)f(xn)

这个数字序列收敛到 f f f的最接近 x 0 \boldsymbol{x}_0 x0的根。

要使用牛顿-拉夫森方法为函数 f ( x ) = x 2 − 3 \boldsymbol{f}\left( \boldsymbol{x} \right) =\boldsymbol{x}^2-3 f(x)=x23求根,请注意 f ′ ( x ) = 2 x \boldsymbol{f}^{\prime}\left( \boldsymbol{x} \right) =2\boldsymbol{x} f(x)=2x,因此,迭代方法的形式为:

x ( n + 1 ) = x ( n ) − f ( x ( n ) ) f ′ ( x ( n ) ) = x ( n ) − ( x ( n ) 2 − 3 ) 2 x ( n ) \boldsymbol{x}^{\left( \boldsymbol{n}+1 \right)}=\boldsymbol{x}^{\left( \boldsymbol{n} \right)}-\frac{\boldsymbol{f}\left( \boldsymbol{x}^{\left( \boldsymbol{n} \right)} \right)}{\boldsymbol{f}^{\prime}\left( \boldsymbol{x}^{\left( \boldsymbol{n} \right)} \right)}=\boldsymbol{x}^{\left( \boldsymbol{n} \right)}-\frac{\left( \boldsymbol{x}^{\left( \boldsymbol{n} \right) ^2}-3 \right)}{2\boldsymbol{x}^{\left( \boldsymbol{n} \right)}} x(n+1)=x(n)f(x(n))f(x(n))=x(n)2x(n)(x(n)23)

MATLAB函数NewtonRaphson.m实现了NewtonRaphson方法:

function [x, Iter] = NewtonRaphson(f, fp, x0, Epsilon)
	 Iter = 0 ;
	 x1 = x0 - f(x0)/fp(x0) ;
	 while abs(f(x1)) ≥ Epsilon
		 x0 = x1 ;
		 x1 = x0 - f(x0)/fp(x0) ;
		 Iter = Iter + 1 ;
	 end
	 x = x1 ;

从命令提示符处调用NewtonRaphson函数:

>> format long
>> f = @(x)2 - 3 ;
>> fp = @(x) 2*x ;
>> Epsilon = 1e-8 ;
>> x0 = 1 ;
>>[x, Iterations] = NewtonRaphson(f, fp, x0, Epsilon)
x =
1.732050810014728
Iterations =
3
>> [x, Iterations] = NewtonRaphson(f, fp, -x0, Epsilon)
x =
-1.732050810014728
Iterations =
3

Python函数NewtonRaphson的代码为:


一次运行上述代码 x 0 = 1.0 \boldsymbol{x}_0=1.0 x0=1.0,另一次运行 x 0 = − 1.0 \boldsymbol{x}_0=-1.0 x0=1.0

In [6]: x, Iters = NewtonRaphson(f, fp, x0, Eps)
In [7]: print(’Approximate root is:, x, ’\nIterations:, Iters)
Approximate root is: 1.7320508100147276
Iterations: 4
In [8]: x, Iters = NewtonRaphson(f, fp, -x0, Eps)
In [9]: print(’Approximate root is:, x, ’\nIterations:, Iters)
Approximate root is: -1.7320508100147276
Iterations: 4

割线法

割线法与牛顿-拉夫森法具有近似的形式,但是它不需要解析形式为 x n ( f ′ ( x n ) ) \boldsymbol{x}_{\boldsymbol{n}}\left( \boldsymbol{f}^{\prime}\left( \boldsymbol{x}_{\boldsymbol{n}} \right) \right) xn(f(xn)) f ( x ) \boldsymbol{f}\left( \boldsymbol{x} \right) f(x) 的导数。 它将 f ′ ( x n ) \boldsymbol{f}^{\prime}\left( \boldsymbol{x}_{\boldsymbol{n}} \right) f(xn) 替换为有限差分公式:

f ′ ( x n ) ≈ f ( x n ) − f ( x n − 1 ) x n − x n − 1 \boldsymbol{f}^{\prime}\left( \boldsymbol{x}_{\boldsymbol{n}} \right) \approx \frac{\boldsymbol{f}\left( \boldsymbol{x}_{\boldsymbol{n}} \right) -\boldsymbol{f}\left( \boldsymbol{x}_{\boldsymbol{n}}-1 \right)}{\boldsymbol{x}_{\boldsymbol{n}}-\boldsymbol{x}_{\boldsymbol{n}-1}} f(xn)xnxn1f(xn)f(xn1)

因此,割线方法的形式为:

x n + 1 = x n − x n − x n − 1 f ( x n ) − f ( x n − 1 ) f ( x n ) \boldsymbol{x}_{\boldsymbol{n}+1}=\boldsymbol{x}_{\boldsymbol{n}}-\frac{\boldsymbol{x}_{\boldsymbol{n}}-\boldsymbol{x}_{\boldsymbol{n}-1}}{\boldsymbol{f}\left( \boldsymbol{x}_{\boldsymbol{n}} \right) -\boldsymbol{f}\left( \boldsymbol{x}_{\boldsymbol{n}-1} \right)}\boldsymbol{f}\left( \boldsymbol{x}_{\boldsymbol{n}} \right) xn+1=xnf(xn)f(xn1)xnxn1f(xn)

从某个包含 f ( x ) \boldsymbol{f}\left( \boldsymbol{x} \right) f(x) 根的间隔 [ a , b ] \left[ \boldsymbol{a},\boldsymbol{b} \right] [a,b] 开始,割线方法迭代逼近 [ a , b ] \left[ \boldsymbol{a},\boldsymbol{b} \right] [a,b] f ( x ) \boldsymbol{f}\left( \boldsymbol{x} \right) f(x) 的零。

MATLAB函数Secant实现割线方法。 它接收一个函数 f f f,其间隔 [ a , b ] \left[ \boldsymbol{a},\boldsymbol{b} \right] [a,b] 的界限包含 f f f的根,并且公差 ε > 0 \boldsymbol{\varepsilon }>0 ε>0。它应用割线方法返回近似解 x x x和迭代次数。

function [x, Iterations] = Secant(f, a, b, Eps)
	 x = b - ((b-a)*f(b))/(f(b)-f(a)) ;
	 Iterations = 1 ;
	 while fabs(f(x)) ≥ Eps
		 a = b ;
		 b = x ;
		 x = b - ((b-a)*f(b))/(f(b)-f(a)) ;
		 Iterations = Iterations + 1 ;
	 end

调用MATLAB函数以找到 x 2 − 3 = 0 \boldsymbol{x}^2-3=0 x23=0的近似根,如下所示。

>> f = @(x) xˆ2-3 ;
>> a = 1; b = 2 ;
>> Eps = 1e-8 ;
>> [x, Iterations] = Secant(f, a, b, Eps)
x =
1.732050807565499
Iterations =
5

函数Secant的Python代码如下。


为了找到等式 x 2 − 3 = 0 \boldsymbol{x}^2-3=0 x23=0的根,使用了以下Python指令:


固定点的迭代方法

x ∗ \boldsymbol{x}^* x是函数 g ( x ) \boldsymbol{g}\left( \boldsymbol{x} \right) g(x) 的不动点,如果

g ( x ∗ ) = x ∗ \boldsymbol{g}\left( \boldsymbol{x}^* \right) =\boldsymbol{x}^* g(x)=x

假设函数 f ( x ) \boldsymbol{f}\left( \boldsymbol{x} \right) f(x) 是可微的,可以写成

f ( x ) = g ( x ) − x \boldsymbol{f}\left( \boldsymbol{x} \right) =\boldsymbol{g}\left( \boldsymbol{x} \right) -\boldsymbol{x} f(x)=g(x)x

如果 x 1 x_1 x1 f ( x ) \boldsymbol{f}\left( \boldsymbol{x} \right) f(x) 的根,则

f ( x 1 ) = g ( x 1 ) − x 1 = 0 ⟹ x 1 = g ( x 1 ) \boldsymbol{f}\left( \boldsymbol{x}_1 \right) =\boldsymbol{g}\left( \boldsymbol{x}_1 \right) -\boldsymbol{x}_1=0\Longrightarrow \boldsymbol{x}_1=\boldsymbol{g}\left( \boldsymbol{x}_1 \right) f(x1)=g(x1)x1=0x1=g(x1)

这意味着 x 1 x_1 x1是函数 g ( x ) \boldsymbol{g}\left( \boldsymbol{x} \right) g(x) 的不动点。 朝固定点进行迭代的方法的思想是将函数 f ( x ) \boldsymbol{f}\left( \boldsymbol{x} \right) f(x) 编写为 g ( x ) − x \boldsymbol{g}\left( \boldsymbol{x} \right) -\boldsymbol{x} g(x)x的形状,并从一些初始猜测 x 0 x_0 x0开始,该方法生成数字 x 0 , x 1 , x 2 , ⋯ \boldsymbol{x}_0,\boldsymbol{x}_1,\boldsymbol{x}_2,\cdots x0,x1,x2, 的序列,使用迭代规则收敛到函数 g ( x ) \boldsymbol{g}\left( \boldsymbol{x} \right) g(x) 的固定点:

x n + 1 = g ( x n ) \boldsymbol{x}_{\boldsymbol{n}+1}=\boldsymbol{g}\left( \boldsymbol{x}_{\boldsymbol{n}} \right) xn+1=g(xn)

为了说明迭代方法的工作原理,将使用它来找到函数的根

f ( x ) = x 2 − 3 \boldsymbol{f}\left( \boldsymbol{x} \right) =\boldsymbol{x}^2-3 f(x)=x23

首先,函数 x 2 − 3 \boldsymbol{x}^2-3 x23 g ( x ) − x \boldsymbol{g}\left( \boldsymbol{x} \right) -\boldsymbol{x} g(x)x的形式编写。 一种可能的选择是编写:

f ( x ) = x 2 − 3 = x 2 + 2 x + 1 − 2 x − 4 = ( x + 1 ) 2 − 2 x − 4 \boldsymbol{f}\left( \boldsymbol{x} \right) =\boldsymbol{x}^2-3=\boldsymbol{x}^2+2\boldsymbol{x}+1-2\boldsymbol{x}-4=\left( \boldsymbol{x}+1 \right) ^2-2\boldsymbol{x}-4 f(x)=x23=x2+2x+12x4=(x+1)22x4

如果 x ∗ \boldsymbol{x}^* x f ( x ) \boldsymbol{f}\left( \boldsymbol{x} \right) f(x) 的根,则:

f ( x ∗ ) = ( x ∗ + 1 ) 2 − 2 x ∗ − 4 = 0 \boldsymbol{f}\left( \boldsymbol{x}^* \right) =\left( \boldsymbol{x}^*+1 \right) ^2-2\boldsymbol{x}^*-4=0 f(x)=(x+1)22x4=0

从中得出,

x ∗ = ( x ∗ + 1 ) 2 − 4 2 \boldsymbol{x}^*=\frac{\left( \boldsymbol{x}^*+1 \right) ^2-4}{2} x=2(x+1)24

从初始点 x 0 x_0 x0开始,为 f ( x ) \boldsymbol{f}\left( \boldsymbol{x} \right) f(x) 求根的迭代方法是:

使用MATLAB和Python solve函数

使用非线性方程组

详情请参考 - 亚图跨际

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值