使用 newton迭代方法计算方程某一区间的值代码_方程求根-二分法、牛顿法、割线法(Python)...

这篇博客整理了计算物理课程中的方程求根方法,包括二分法、牛顿法和割线法(分立牛顿法)。通过迭代计算,牛顿法和割线法在满足误差要求的情况下,相比二分法展现出更高的效率。文中详细介绍了每种方法的数学基础、迭代公式和实际应用,并指出牛顿法在某些情况下的局限性。
摘要由CSDN通过智能技术生成

53894f8c27e23dc5e1c73af2e7304ec6.png

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

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

二分法

数学基础:对于连续函数

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 即为牛顿法迭代公式。

f4654232a056213506d67ce3100e80e7.png

在迭代公式中,每一个

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:

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值