许多复杂的求解问题,都可以转换成方程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]内的数可以作为方程的近似解。
求方程式: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
对比牛顿迭代法,牛顿迭代法要快很多,而且准确率也高
牛顿迭代法(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 的含义是精度