区间二分法(Bisection Method)迭代求根的python程序

迭代法的作用

许多复杂的求解问题,都可以转换成方程f(x)=0的求解问题。这一系列的解叫做方程的根。对于非线性方程的求解,在自变量范围内往往有多个解,我们将此变化区域分为多个小的子区间,对每个区间进行分别求解。我们在求解过程中,选取一个近似值或者近似区间,然后运用迭代方法逐步逼近真实解。
方程求根的常用迭代法有:二分法、不动点迭代、牛顿法、弦截法。

二分法

求实根最简单有效的方法:二分法。易于在计算机上实现,且对于函数f(x)的性质要求不高,仅仅要求它在有根区间上连续,且区间端点的函数值异号即可。它的缺点是不能求偶数重根,也不能求复根,收敛速度与以1/2为公比的等比数列相同,不算太快,因此一般在求方程近似根时,不太单独使用,常用它来为其他方法求方程近似根提供好的初值区间(重要:初值区间的确定直接决定求解的速度)。

二分法基本思想

把函数f(x)的零点所在的区间[a,b](满足f(a)×f(b)<0)“一分为二”,得到[a,m]和[m,b]。根据“f(a)●f(m)<0”是否成立,取出零点所在的区间[a,m]或[m,b],仍记为[a,b]。所对得的区间[a,b]重复上述步骤,直到包含零点的区间[a,b]“足够小”,则[a,b]内的数可以作为方程的近似解。

二分法计算步骤

区间二分法(Bisection Method)迭代求根的python程序_第1张图片
详细步骤:



例题

求方程式:x3 - 0.165*x2 + 3.993*10**(-4) = 0在(0,0.11)的根

牛刀小试
代码:

xl = 0
xu = 0.11

def f(x):
    f = x**3 - 0.165*x**2 + 3.993*10**(-4)  #需要求根的函数
    return f

for i in range(100):     #进行100次迭代,迭代次数自己定
    xm = (xl + xu) / 2
    if f(xm) == 0:
        break
    else:
        pass
    if f(xl) * f(xm) < 0:
        xl =xl
        xu = xm
    elif f(xl) * f(xm) > 0:
        xl = xm
        xu = xu
    else:
        break
print(xl , xu)
print('方程的根为:', (xl + xu) / 2)

结果:

0.06237758151374948 0.06237758151374953
方程的根为: 0.0623775815137495

约定一个误差,当误差小于某个数值的时候,迭代停止
代码如下:

xl = 0
xu = 0.11

def f(x):
    f = x**3 - 0.165*x**2 + 3.993*10**(-4)  #需要求根的函数
    return f

xm_list = []
m = 0
while True:
    xm = (xl + xu) / 2
    xm_list.append(xm)
    m += 1
    if f(xm) == 0:
        break
    else:
        pass
    if f(xl) * f(xm) < 0:
        xl =xl
        xu = xm
    elif f(xl) * f(xm) > 0:
        xl = xm
        xu = xu
    else:
        break
    if len(xm_list) > 1:
        error = abs((xm_list[-1] - xm_list[-2]) / xm_list[-1])
        if error < 10 ** (-6):
            print(f'迭代第{m}次后,误差小于10^(-6),误差为{error}')
            break
    else:
        pass
print(xl , xu)
print(f'得到方程的根为:{(xl + xu) / 2}')

结果:

迭代第21次后,误差小于10^(-6),误差为8.408809405129639e-07
0.062377543449401864 0.062377595901489266
得到方程的根为:0.06237756967544557

迭代至电脑默认误差为0

xl = 0
xu = 0.11

def f(x):
    f = x**3 - 0.165*x**2 + 3.993*10**(-4)  #需要求根的函数
    return f

m = 0
while True:
    xm = (xl + xu) / 2
    m += 1
    if f(xm) == 0:
        break
    else:
        pass
    if f(xl) * f(xm) < 0:
        xl =xl
        xu = xm
    elif f(xl) * f(xm) > 0:
        xl = xm
        xu = xu
    else:
        break
print(xl , xu)
print(f'迭代第{m}次后,误差为0,得到方程的根为:{(xl + xu) / 2}')

结果:

0.06237758151374948 0.06237758151374953
迭代第52次后,误差为0,得到方程的根为:0.0623775815137495

画迭代图
代码:

import matplotlib.pyplot as plt
xl = 0
xu = 0.11

def f(x):
    f = x**3 - 0.165*x**2 + 3.993*10**(-4)  #需要求根的函数
    return f

xm_list = []
x_values = []
y_values = []
m = 0
while True:
    xm = (xl + xu) / 2
    xm_list.append(xm)
    m += 1
    if f(xm) == 0:
        break
    else:
        pass
    if f(xl) * f(xm) < 0:
        xl =xl
        xu = xm
    elif f(xl) * f(xm) > 0:
        xl = xm
        xu = xu
    else:
        break
    if len(xm_list) > 1:
        error = abs((xm_list[-1] - xm_list[-2]) / xm_list[-1])
        x_values.append(m)
        y_values.append(error)
        if error == 0:
            break
    else:
        pass
print(f'xl={xl},xu={xu}')
print(f'迭代第{m}次后,误差为0,得到方程的根为:{(xl + xu) / 2}')

#设置绘图风格
plt.style.use('ggplot')
#处理中文乱码
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
#坐标轴负号的处理
plt.rcParams['axes.unicode_minus']=False
#横坐标是迭代次数
#纵坐标是误差值
plt.plot(x_values,
         y_values,
         color = 'steelblue', # 折线颜色
         marker = 'o', # 折线图中添加圆点
         markersize = 3, # 点的大小
         )
# 修改x轴和y轴标签
plt.xlabel('迭代次数')
plt.ylabel('误差值')
# 显示图形
plt.show()

结果:

xl=0.06237758151374948,xu=0.06237758151374953
迭代第52次后,误差为0,得到方程的根为:0.0623775815137495

区间二分法(Bisection Method)迭代求根的python程序_第2张图片
对比牛顿迭代法,牛顿迭代法要快很多,而且准确率也高
牛顿迭代法(Newton’s Method)迭代求根的Python程序

不用迭代,直接得到高次方程的解:

from sympy import *
from sympy.abc import x

def func(x):
    return x**3 - 0.165*x**2 + 3.993*10**(-4)
result = solve(func(x),x)
print(result)

结果:

[-0.0437370862084818 + 0.e-24*I, 0.0623775815137495 + 0.e-22*I, 0.146359504694732 - 0.e-24*I]

【问题】
0.e-24*I 到底是什么含义呢?
有路过的大神看到了,请帮忙在评论区解答一下
【解答】

from sympy import *
from sympy.abc import x

def func(x):
    return x**3 - 0.165*x**2 + 3.993*10**(-4)
result = solveset(func(x), x, Interval(-1, 1))
print(result)

结果:

FiniteSet(-0.0437370862084818, 0.0623775815137495, 0.146359504694732)

所以0.e-24*I 的含义是精度

你可能感兴趣的:(算法,python,二分法,迭代求根)