本文已参与「新人创作礼」活动,一起开启掘金创作之路。
0. 问题描述
给定一个复杂方程,如果直接求解其解析解非常复杂或者难以求解的话,那么可以通过数值求解的方法得到一定精度条件下的数值解。
1. 实根的对分法
对分法使用的条件需要满足:
- 在区间上连续;
- ;
那么,在区间中必然存在至少一个零点,我们可以使用二分法不断地迭代求解。
给出python伪代码如下:
def bisect_solve(fn, a, b, epsilon=1e-9):
assert(fn(a) * fn(b) < 0)
while b - a >= epsilon:
m = (a + b)/2
if fn(m) * fn(a) > 0:
a = m
elif fn(m) * fn(b) > 0:
b = m
else:
return m
return (a+b)/2
2. 迭代法
迭代法的思路是说,将方程 改写为方程。
此时,我们可以构造迭代关系,如果数列收敛,那么数列的极限 即为目标方程的解。
而关于数列的收敛条件的判断,我们有定理:
定理 4.1
若定义在上,且满足:
(1) 当时,有;
(2) 在上可到,且存在正数,使得对于任意,有;
则在上有唯一的点满足,称为的不动点,且迭代格式对任意的初值均收敛于的不动点,且有误差估计式:
同样的,我们可以给出python伪代码实现如下:
def iter_solve(fn, x, epsilon=1e-9):
MAX_ITER_TIME = 10**7
for _ in range(MAX_ITER_TIME):
y = fn(x)
if abs(y-x) <= epsilon:
return y
x = y
return x
3. Newton迭代法
Newton迭代法的思路来源于泰勒展开,给出Talyer展开公式如下:
如果视二阶以上的结果为小量,则有:
当为零点时,有,因此,我们近似即有:
由此,我们即可给出Newton迭代公式如下:
其物理含义是说:
- 每次在曲线的某一个点上做一条切线,取该切线与x轴的交点作为下一个迭代点。
给出python伪代码如下:
def newton_solve(fn, dfn, x, epsilon=1e-9):
MAX_ITER_TIME = 10**7
for _ in range(MAX_ITER_TIME):
y = x - fn(x)/dfn(x)
if abs(y-x) <= epsilon:
return y
x = y
return x
4. 弦截法
弦截法其实就是Newton迭代法的一个近似版本,具体来说,就是将导数用弦截公式进行替换。
给出弦截法的迭代公式如下:
同样给出python伪代码如下:
def secant_solve(fn, x1, x0, epsilon=1e-9):
MAX_ITER_TIME = 10**7
for _ in range(MAX_ITER_TIME):
y = x1 - fn(x1) * (x1 - x0) / (fn(x1) - fn(x0))
if abs(y-x1) <= epsilon:
return y
x1, x0 = y, x1
return x