Python数值方程根

69 篇文章 5 订阅
11 篇文章 1 订阅

工程分析中遇到的一个常见问题如下:给定函数 f ( x ) f(x) f(x),确定 f ( x ) = 0 f(x)=0 f(x)=0 x x x的值。解( x x x的值)被称为方程 f ( x ) = 0 f(x)=0 f(x)=0的根。

在继续进行之前,回顾一下函数的概念可能会有所帮助。 等式

y = f ( x ) y=f(x) y=f(x)

包含三个元素:输入值 x x x,输出值 y y y和计算 y y y的规则 f f f。 如果指定了规则 f f f,则称指定该函数。 在数值计算中,规则始终是计算机算法。 它可能是一个函数语句,例如

f ( x ) = cosh ⁡ ( x ) cos ⁡ ( x ) − 1 f(x)=\cosh (x) \cos (x)-1 f(x)=cosh(x)cos(x)1

或包含数百或数千行代码的复杂过程。 只要算法为每个输入 x x x生成输出 y y y,它就可以作为函数

方程的根可以是实数,也可以是复数。 复数根很少计算,因为它们几乎没有物理意义。 多项式方程式是一个例外

a 0 + a 1 x + a 1 x 2 + ⋯ + a n x n = 0 a_{0}+a_{1} x+a_{1} x^{2}+\cdots+a_{n} x^{n}=0 a0+a1x+a1x2++anxn=0

复数根可能有意义的地方(例如,在阻尼振动分析中)。

通常,方程式可以具有任意数量的(实数)根或根本没有根。 例如,

sin ⁡ x − x = 0 \sin x-x=0 sinxx=0

有一个根,即 x = 0 x=0 x=0,而

tan ⁡ x − x = 0 \tan x-x=0 tanxx=0

有无限数量的根 ( x = 0 , ± 4.493 , ± 7.725 , … ) (x=0,\pm 4.493,\pm 7.725, \ldots) (x=0,±4.493,±7.725,)

所有找到根的方法都是需要起点(即,对根的估计)的迭代过程。 这个估计至关重要。 错误的起始值可能无法收敛,或者可能收敛到“错误”的根(与所求根不同的根)。 尚无用于估计根值的通用方法。 如果方程与物理问题相关联,则问题的上下文(物理洞察力)可能会建议根的大概位置。 否则,您可以对根进行系统的数值搜索。绘制函数是定位根的另一种方法,但这是无法编程的视觉过程。

增量搜索法

根的近似位置最好通过绘制函数来确定。 通常,基于一些点的非常粗糙的图就足以提供合理的起始值。 用于检测和括弧的另一个有用工具是增量搜索方法。 它也可以适用于计算根,但是这样做并不值得,因为本文中介绍的其他方法对于完成该任务更为有效。

增量搜索方法背后的基本思想很简单:如果 f ( x 1 ) f\left(x_{1}\right) f(x1) f ( x 2 ) f\left(x_{2}\right) f(x2)具有相反的符号,则间隔 ( x 1 , x 2 ) \left(x_{1}, x_{2}\right) (x1,x2)中至少有一个根。 如果间隔足够小,则很可能包含单个根。 因此,可以通过在间隔 Δ x \Delta x Δx处评估函数并寻找符号变化来检测 f ( x ) f(x) f(x)的零。

增量搜索方法存在一些潜在的问题:

  • 如果搜索增量 Δ x \Delta x Δx大于两个根的间距,则有可能会丢失两个紧密间隔的根。
  • 不会检测到双根(两个根重合)。
  • f ( x ) f(x) f(x)的某些奇点(极点)可能被误认为是根。 例如, f ( x ) = tan ⁡ x f(x)=\tan x f(x)=tanx会在 x = ± 1 2 n π , n = 1 , 3 , 5 , … x=\pm \frac{1}{2} n \pi, n=1,3,5, \ldots x=±21nπ,n=1,3,5,处改变符号,如图1所示。 但是,这些位置不是真正的零,因为该函数不与 x x x轴交叉。

图1

算法代码

rootsearch函数在间隔 ( a , b ) (a, b) (a,b)中以 d x dx dx的增量搜索用户提供的函数 f ( x ) f(x) f(x)的零。 如果搜索成功,则返回根的边界 ( x 1 , x 2 ) (\mathrm{x} 1, \mathrm{x} 2) (x1,x2);否则,返回根的边界。 x 1 = x 2 =  None  \mathrm{x} 1=\mathrm{x} 2=\text { None } x1=x2= None 表示未检测到根。 在检测到第一个根(最接近 a a a的根)之后,可以再次调用rootsearch并用 x 2 x2 x2代替,以查找下一个根。 只要rootsearch检测到根,就可以重复执行此操作。

## module rootsearch
’’’ x1,x2 = rootsearch(f,a,b,dx).
		Searches the interval (a,b) in increments dx for
		the bounds (x1,x2) of the smallest root of f(x).
		Returns x1 = x2 = None if no roots were detected.
’’’
from numpy import sign
def rootsearch(f,a,b,dx):
		x1 = a; f1 = f(a)
		x2 = a + dx; f2 = f(x2)
		while sign(f1) == sign(f2):
				if x1 >= b: return None,None
				x1 = x2; f1 = f2
				x2 = x1 + dx; f2 = f(x2)
		else:
				return x1,x2

示例1

x 3 − 10 x 2 + 5 = 0 x^{3}-10 x^{2}+5=0 x310x2+5=0的根位于间隔 ( 0 , 1 ) (0,1) (0,1)中。 使用rootsearch函数可以四位数精度计算此根。

为了获得四位数的精度,我们需要不大于 Δ x = 0.0001 \Delta x=0.0001 Δx=0.0001的搜索增量。 因此,以增量 x x x搜索间隔(0,1)将需要10,000个功能评估。 下面的程序通过在四个阶段中接近根,将函数评估的数量减少到40个,每个阶段涉及10个搜索间隔(因此需要10个函数评估)。

二分法

在间隔 ( x 1 , x 2 ) \left(x_{1}, x_{2}\right) (x1,x2)中将 f ( x ) = 0 f(x)=0 f(x)=0的根括弧后,可以使用几种方法对其进行接近。 对分方法通过将间隔连续减半直到间隔变得足够小来实现此目的。 此技术也称为间隔减半方法。 二等分不是用于计算根的最快方法,但它是最可靠的方法。 一旦将一个方括号括起来,二等分将始终在其上闭合。

二等分的方法使用与增量搜索相同的原理:如果区间 ( x 1 , x 2 ) \left(x_{1}, x_{2}\right) (x1,x2)中有根,则 f ( x 1 ) f\left(x_{1}\right) f(x1) f ( x 2 ) f\left(x_{2}\right) f(x2)具有相反的符号。 为了将间隔减半,我们计算 f ( x 3 ) f\left(x_{3}\right) f(x3),其中 x 3 = 1 2 ( x 1 + x 2 ) x_{3}=\frac{1}{2}\left(x_{1}+x_{2}\right) x3=21(x1+x2)是间隔的中点。 如果 f ( x 2 ) f\left(x_{2}\right) f(x2) f ( x 3 ) f\left(x_{3}\right) f(x3)具有相反的符号,则根必须在 ( x 2 , x 3 ) \left(x_{2}, x_{3}\right) (x2,x3)中,并且我们通过用 x 3 x_{3} x3替换原始绑定 x 1 x_{1} x1来记录它。 否则,根位于 ( x 1 , x 3 ) \left(x_{1}, x_{3}\right) (x1,x3)中,在这种情况下, x 2 x_{2} x2将替换为 x 3 x_{3} x3。 无论哪种情况,新间隔 ( x 1 , x 2 ) \left(x_{1}, x_{2}\right) (x1,x2)都是原始间隔的一半。 重复二等分,直到间隔减小到较小的值 ε \varepsilon ε,于是

∣ x 2 − x 1 ∣ ≤ ε \left|x_{2}-x_{1}\right| \leq \varepsilon x2x1ε

计算达到规定的 ε \varepsilon ε所需的平分数量很容易。 一个二等分后,原始间隔 Δ x \Delta x Δx减少为 Δ x / 2 \Delta x / 2 Δx/2,两个二等分后为 Δ x / 2 2 \Delta x / 2^{2} Δx/22 n n n个二等分后为 Δ x / 2 n \Delta x / 2^{n} Δx/2n。设定 Δ x / 2 n = ε \Delta x / 2^{n}=\varepsilon Δx/2n=ε,对n求解,我们得到

n = ln ⁡ ( Δ x / ε ) ln ⁡ 2 , ( 1 ) n=\frac{\ln (\Delta x / \varepsilon)}{\ln 2},\qquad(1) n=ln2ln(Δx/ε),(1)

由于 n n n必须为整数,因此使用 n n n的上限( n n n的上限是大于 n n n的最小整数)。

算法代码

bisection函数使用二分法计算已知位于区间 ( x 1 , x 2 ) \left(x_{1}, x_{2}\right) (x1,x2)中的 f ( x ) = 0 f(x)=0 f(x)=0的根。 根据公式(1)可计算出将间隔减小到tol所需的二分数量n。通过将  switch  = 1 \text { switch }=1  switch =1,我们强制例程检查 f ( x ) f(x) f(x)的幅度是否随着每个间隔减半而减小。 如果不是,则可能是错误的(可能“根”根本不是根,而是一个极点),并且返回root = None。 由于并非总是需要此功能,因此默认值为  switch  = 0 \text { switch }=0  switch =0。韩数error.err用来终止程序。

示例2

使用二分法找到 x 3 − 10 x 2 + 5 = 0 x^{3}-10 x^{2}+5=0 x310x2+5=0的根,该根位于 ( 0 , 1 ) (0,1) (0,1)到四位精度之间(此问题已在示例1中通过rootsearch解决了)。 该过程涉及多少功能评估?

代码如下:

请注意,我们将 ε = 0.0001 \varepsilon=0.0001 ε=0.0001(二分中 t o l = 1.0 e − 4 \mathrm{tol}=1.0 \mathrm{e}-4 tol=1.0e4)设置为将精度限制为四个有效数字。 结果是

依据等式(1)

n = ln ⁡ ( ∣ Δ x ∣ / ε ) ln ⁡ 2 = ln ⁡ ( 1.0 / 0.0001 ln ⁡ 2 = 13.29 n=\frac{\ln (|\Delta x| / \varepsilon)}{\ln 2}=\frac{\ln (1.0 / 0.0001}{\ln 2}=13.29 n=ln2ln(Δx/ε)=ln2ln(1.0/0.0001=13.29

因此,二分法的for循环中的函数求值数为 ⌈ 13.29 ⌉ = 14 \lceil 13.29\rceil=14 13.29=14。在子例程的开头有另外2个求值,总共有16个函数求值。

示例3

用二分法求出区间(0,20)中 f ( x ) = x − tan ⁡ x f(x)=x-\tan x f(x)=xtanx的所有零。 使用函数rootsearch和bisection。

请注意,tan x是奇异的,并且在x =π/ 2,3π/ 2,…处更改正负号。为防止二等分将这些点误认为是根,我们将switch设置为1。根与奇异点的接近度是另一个潜在的问题,可以通过在根搜索中使用小 Δ x \Delta x Δx来缓解。 选择 Δ x = 0.01 \Delta x=0.01 Δx=0.01,我们得出以下结果代码:

详情参阅 - 亚图跨际

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值