|
对于方程 f(x)=0, 假如已知区间(a,b)必有根(通过f(a)f(b)<0判断),
要在数值上精确求得其根通常用二分法:
为讨论方便设计算过程中不会刚好取到 f(m)=0
| 1) m=(a+b)/2
2) f(m)f(a)>0吗? 是则令a=m, 否则令 b=m
3) 达到精度要求了吗? 是则输出m,
否则返回(1) |
函数曲线的一种情况. |
f(m)f(a)>0 这一步不需真的做乘法.
可以想象的出, 对于多数函数 a,b中点是一个不差的选择,
每次可以缩小根区间的一半.
很容易的, 马上会想到多数常见函数在a-b较小时函数会比较"直",
取过(a,f(a)) (b,f(b))的直线与x轴的交点可能会更好:
直线方程: y=((f(b)-f(a))/(b-a))(x-a)+f(a),
y=0 时 x=-f(a)*(b-a)/(f(b)-f(a))+a.
于是有以下算法:
| 1) m=-f(a)*(b-a)/(f(b)-f(a))+a
2) f(m)f(a)>0吗? 是则令a=m, 否则令 b=m
3) 达到精度要求了吗? 是则输出m,
否则返回(1) |
 |
不过这一算法有个问题,
由于函数在这一区间很可能只是凹的或凸的, 于是f(m)的符号总是不变,
a或b也总是保持原有的值, 影响收敛速度,
根区间基本不再缩小(难以确定根的精度).与二分法交替使用也许会有些改进.
| 1) m=-f(a)*(b-a)/(f(b)-f(a))+a
2) f(m)f(a)>0吗? 是则令a=m, 否则令 b=m
3) 需要二分法修正吗? 是则
a) 令 m=(a+b)/2
b) f(m)f(a)>0吗? 是则令a=m,
否则令 b=m
4) 达到精度要求了吗? 是则输出m,
否则返回(1)
|
至于牛顿迭代法则是取一个端点的切线,
把切线与x轴的交点作为更好的根的逼近.
切线方程(假设作(b,f(b))的切线): y=f'(b)(x-b)+f(b),
y=0 时 x=-f(b)/f'(b)+b. f'(x)是f(x)的导函数,
见微积分.
于是有以下算法:
| 1) x=x-f(x)/f'(x)
2) x不属于[a,b]吗? 是则停止计算(计算失败).
3) 达到精度要求了吗? 是则输出x,
否则返回(1) |
 |
举一个实例, 解 sin(3x)-x=0, 已知在(0.5,1)内有根.
| 次数 |
二分法 |
割线法 |
割线-二分法 |
牛顿迭代 |
| 1 |
0.75000<x<1.00000 |
0.683391391 |
0.75 |
0.783656206 |
| 2 |
0.75000<x<0.87500 |
0.744132189 |
0.757912818 |
0.760228866 |
| 3 |
0.75000<x<0.81250 |
0.756837815 |
0.759322531 |
0.759621314 |
| 4 |
0.75000<x<0.78125 |
0.759133678 |
0.759568923 |
0.759620887 |
| 5 |
0.75000<x<0.76562 |
0.759535998 |
0.759611841 |
0.759620887 |
| 6 |
0.75781<x<0.76562 |
0.759606108 |
0.759611841 |
|
| 7 |
0.75781<x<0.76171 |
0.759618314 |
0.759619893 |
|
| 8 |
0.75781<x<0.75976 |
0.759620439 |
0.759620777 |
|
| 9 |
0.75878<x<0.75976 |
0.759620809 |
0.759620875 |
|
| 10 |
0.75927<x<0.75976 |
0.759620873 |
0.759620885 |
|
 |
| y=sin(3x)-x 的函数图像 |
再举一例, 解 x/ln(x)-20=0, 已知在(60,110)内有根.
图像几乎是一根直线.
| 次数 |
二分法 |
割线法 |
割线-二分法 |
牛顿迭代 |
| 1 |
85.000<x<110.00 |
90.55523161 |
85.0000000000<x<110.000000000 |
89.68844057 |
| 2 |
85.000<x<97.500 |
90.01194878 |
85.0000000000<x<90.0787731363 |
89.99502264 |
| 3 |
85.000<x<91.250 |
89.99561333 |
85.0000000000<x<89.9954814451 |
89.99510577 |
| 4 |
88.125<x<91.250 |
89.99512107 |
85.0000000000<x<89.9951074578 |
89.99510577 |
| 5 |
89.687<x<91.250 |
89.99510623 |
85.0000000000<x<89.9951057780 |
|
| 6 |
89.687<x<90.468 |
89.99510578 |
87.4975528890<x<89.9951057780 |
|
| 7 |
89.687<x<90.078 |
89.99510577 |
87.4975528890<x<89.9951057705 |
|
| 8 |
89.882<x<90.078 |
89.99510577 |
87.4975528890<x<89.9951057705 |
|
| 9 |
89.980<x<90.078 |
89.99510577 |
89.9951057705<x<89.9951057705 |
|
| 10 |
89.980<x<90.029 |
|
|
|
可以看到, 二分法收敛速度慢而稳,
割线法对于较直的函数也比较快.
而牛顿迭代法只需几步就完成计算, 非常快.
{ 生这些数据的程序 root01.pas
, 用Turbo Pascal运行时可能要打开编译开关 {$N+}
以便能使用浮点类型double }
|