python牛顿迭代法求根例题_方程求根-二分法、牛顿法、割线法(Python)

课堂笔记整理:方程求根-二分法、牛顿法、割线法。

内容来自周善贵老师的《计算物理》课程。

二分法

数学基础:对于连续函数

equation?tex=f%28x%29 构成的方程:

equation?tex=f%28x%29%3D0 ,如果在区间

equation?tex=%5Ba%2Cb%5D 上满足:

equation?tex=f%28a%29f%28b%29%3C0 ,则区间

equation?tex=%5Ba%2Cb%5D 内至少存在一点

equation?tex=%5Cepsilon ,使得

equation?tex=f%28%5Cepsilon%29%3D0

基本思想:取区间中点

equation?tex=c%3D%5Cfrac%7Ba%2Bb%7D%7B2%7D ,如果

equation?tex=f%28a%29f%28c%29%3C0 ,则根位于区间

equation?tex=%5Ba%2Cc%5D 内;否则根位于区间

equation?tex=%5Bc%2Cb%5D 内。对根存在的区间继续取中点,以此类推,直到当前根(cur_root)的函数值小于可接受误差为止。

对于方程

equation?tex=f%28x%29%3De%5E%7Bx%7D+%5Cln+x-x%5E%7B2%7D%3D0 ,使用二分法求根的Python代码如下:

import math

def func(cur_root):

func = math.exp(cur_root) * math.log(cur_root) - cur_root ** 2

return func

def binary(convergence, left, right):

print('current acceptable error: ' + str(convergence) + '\n')

error = convergence + 1 # 循环开始条件

cur_root = left

count = 1

while error > convergence:

if abs(func(left)) < convergence:

print('root = ' + str(left))

elif abs(func(right)) < convergence:

print('root = ' + str(left))

else:

print(str(count) + ' root = ' +str(cur_root))

middle = (left + right) / 2

if (func(left) * func(middle)) < 0:

right = middle

else:

left = middle

cur_root = left

error = abs(func(cur_root))

count += 1

convergence = float(input("your acceptable error:"))

left = float(input('left: '))

right = float(input('right: '))

binary(convergence, left, right)

要求误差不高于

equation?tex=0.000001 ,区间取

equation?tex=%5B1%2C4%5D

left: 1

right: 4

current acceptable error: 1e-06

第21步后误差满足条件:

21 root = 1.6945991516113281

牛顿法

将函数在根附近泰勒展开:

equation?tex=f%5Cleft%28x_%7B%5Cmathrm%7Br%7D%7D%5Cright%29+%5Csimeq+f%28x%29%2B%5Cleft%28x_%7B%5Cmathrm%7Br%7D%7D-x%5Cright%29+f%5E%7B%5Cprime%7D%28x%29%2B%5Ccdots%3D0

取线性阶近似,可得:

equation?tex=f%5Cleft%28x_%7Bk%2B1%7D%5Cright%29%3Df%5Cleft%28x_%7Bk%7D%5Cright%29%2B%5Cleft%28x_%7Bk%2B1%7D-x_%7Bk%7D%5Cright%29+f%5E%7B%5Cprime%7D%5Cleft%28x_%7Bk%7D%5Cright%29+%5Csimeq+0

可以解得:

equation?tex=x_%7Bk%2B1%7D%3Dx_%7Bk%7D%2B%5CDelta+x_%7Bk%7D%3Dx_%7Bk%7D-%5Cfrac%7Bf_%7Bk%7D%7D%7B+f_%7Bk%7D%5E%7B%5Cprime%7D%7D 即为牛顿法迭代公式。

在迭代公式中,每一个

equation?tex=x_%7Bk%2B1%7D 都是由

equation?tex=x_%7Bk%7D 减去

equation?tex=%5Cfrac%7B%E5%87%BD%E6%95%B0%E5%80%BC%7D%7B%E5%AF%BC%E6%95%B0%E5%80%BC%7D 得到的。

对于方程

equation?tex=f%28x%29%3De%5E%7Bx%7D+%5Cln+x-x%5E%7B2%7D%3D0 ,使用牛顿法求根的Python代码如下:

import math

def newton(convergence, ini_root):

print('current acceptable error: ' + str(convergence) + '\n')

error = convergence + 1 #循环开始条件

cur_root = ini_root

count = 1 # 迭代计数

while error > convergence:

print(str(count) + ' root = ' +str(cur_root))

func = math.exp(cur_root) * math.log(cur_root) - cur_root**2

dif_func = math.exp(cur_root) * ((1 / cur_root) + math.log(cur_root)) - 2 * cur_root

cur_root = cur_root - func / dif_func # 进行迭代

error = abs(func) # 计算误差

count += 1

convergence = float(input("your acceptable error:"))

ini_root = float(input('your initial root '))

newton(convergence, ini_root)

依然要求误差不高于

equation?tex=0.000001 ,从4开始迭代:

your initial root 4

current acceptable error: 1e-06

只需迭代7次即可结束,比二分法效率高很多:

8 root = 1.6946010436031655

割线法(分立牛顿法)

在牛顿法中,每一步都需要计算当前点的导数值,需要手动求导。如果不想人工求导,可以使用两点割线来代替切线,从而得到割线法,因此割线法又称分立牛顿法。

使用

equation?tex=%28x_%7Bk-1%7D%2Cf%28x_%7Bk-1%7D%29%29

equation?tex=%28x_k%2Cf%28x_k%29%29 两点计算的割线斜率为:

equation?tex=secant%3D%5Cfrac%7Bf%28x_k%29-f%28x_%7Bk-1%7D%29%7D%7Bx_k-x_%7Bk-1%7D%7D

equation?tex=secant 代替牛顿法中的

equation?tex=f%27%28k%29 ,可得割线法迭代式:

equation?tex=x_%7Bk%2B1%7D%3Dx_%7Bk%7D-%5Cfrac%7B%5Cleft%28x_%7Bk%7D-x_%7Bk-1%7D%5Cright%29+f_%7Bk%7D%7D+%7B%5Cleft%28f_%7Bk%7D-f_%7Bk-1%7D%5Cright%29%7D

import math

def func(cur_root):

func = math.exp(cur_root) * math.log(cur_root) - cur_root ** 2

return func

def secant(convergence, x_0, x_1):

print('current acceptable error: ' + str(convergence) + '\n')

error = convergence + 1

cur_root = x_1

count = 1

while error > convergence:

print(str(count) + ' root = ' + str(cur_root))

sect = (func(x_1) - func(x_0)) / (x_1 - x_0)

cur_root = cur_root - func(x_1) / sect

error = abs(func(cur_root))

x_0 = x_1

x_1 = cur_root

count += 1

convergence = float(input("your acceptable error:"))

x_0 = float(input('x_0: '))

x_1 = float(input('x_1: '))

secant(convergence, x_0, x_1)

继续要求误差不高于

equation?tex=0.000001 ,从4开始迭代:

x_0: 4

x_1: 3

current acceptable error: 1e-06

可以在8次迭代之后结束:

9 root = 1.694602010833161

可以看到,牛顿法及其变种割线法,相对于二分法是十分高效的,但是牛顿法也有局限。牛顿法在某些情况下并不收敛,例如牛顿法求方程

equation?tex=f%28x%29%3Dx%5E%7B%5Cfrac%7B1%7D%7B3%7D%7D%3D0 的根,每一次取切线进行迭代都会使当前

equation?tex=x 更加远离方程的根,最终跑到无穷大溢出报错:

1023 root = (inf-1.2158939983623275e+294j)

OverflowError: complex exponentiation

Reference:

周善贵,《计算物理》课程讲义

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值