1. 二分法(Bisection)

1) 原理

  【介值定理】 对于连续的一元非线性函数,若其在两个点的取值异号,则在两点间必定存在零点。

  【迭代流程】 若左右两端取值不同,则取其中点,求其函数值,取中点和与中点取值异号的端点构成新的区间(其中必有零点)。进行下一次迭代。

2) 实现二分求根算法

  使用MATLAB实现二分法代码如下。捕捉异常主要是为了在无法进行二分法的区间内发生输出zeropt为空的错误。

function [ zeropt ] = bisection( func, left, right, prec )
%  二分法找非线性函数零点
% 输入4参数:函数句柄func,上/下界left/right,要求绝对精度prec
% 返回1参数:零点
leftVal = func(left);
rightVal = func(right);
if leftVal*rightVal >= 0 % 捕捉异常:若上下界处符号非相反
error('Function vals at the boundaries are of the same sign, bisection unable to continue!');
end
flag = 0;
while (right - left) > prec % 当区间长度大于精度时
mid = (left + right)/2;
midVal = func(mid);
if midVal == 0 % 若中点值恰好为零则直接得到该值
zeropt = mid;
flag = 1;
break;
end
if midVal*leftVal < 0 % 否则找到取值与中点取值异号的端点,将该区间作为新的查找区间
right = mid;
else
left = mid;
leftVal = midVal;
end
end
if flag == 0 % 若由于区间长度满足精度而退出循环,则取区间中点为零点
zeropt = (left + right)/2;
end

 

  对于任意满足要求的函数(连续)和区间(两端函数值异号),二分法保证能够找到一个满足要求的解。比如输入函数句柄,并执行调用二分法函数,就得到如下结果:

func = @(x)x^3 - 20*x^2 - 25*x + 500;
bisection(func, 0, 15, 0.0001)
ans = 5.0000

  即算出该函数在(0, 15)区间上的一个零点是5.0000.

3) 二分法的迭代步复杂度、收敛速度及其他性质

  【迭代步复杂度】一次求中点,一次函数值求值(由x求y为一次求值)。注意由于每次迭代时只有中点值是没算过的,其他两个值之前都算过可以继续使用,故每次迭代仅一次函数值求值。

  【收敛速度】最大可预期的误差上限为区间长度,而每次迭代恒定地将区间长度减半。$\Rightarrow$ 线性收敛且收敛常数为0.5( $r=1, C=0.5$ ).

  【二分法的优点】1)安全可控:区间总是减半缩小,在区间缩小过程中总是至少有一个零点存在于区间中;2)迭代复杂度很低,完全不考虑函数的性质,仅仅使用一次函数值求值。之后在其他更高效的方法之中,二分法经常被作为起安全保护作用的算法,避免其他算法迭代产生的点位置过于离谱。

  【二分法的缺点】1)完全没有利用函数的性质!太可惜了,放弃了很重要的信息!2)收敛率仅为1,收敛速度缓慢。事实上是几种迭代方法中收敛最慢的两种之一;3)需要一个两端异号的区间作为开头,那如果是一个仅仅在中间较小的一段区域小于零,两侧均为正的函数呢?等到人工搜寻到异号的区间几乎都已经找到零点了!

2. 不动点迭代(Fixed Point Iteration)

1) 原理

  【不动点】 $x=g(x)$ 的解称为函数 $g(x)$ 的不动点,几何图像为函数图像与正比例函数 $y=x$ 的交点。

  【不动点迭代】 迭代形式为:$x_{k+1}=g(x_k)$ 。设函数的不动点为 $x^*$ ,当 $|g'(x^*)|<1$ 时,在不动点附近的存在一个领域,使得从领域内的某个值开始的不动点迭代收敛,收敛到不动点。通过 $\delta x_{k+1}\approx g'(x^*) \delta x_{k}$ 式,当导数绝对值小于1时,迭代后误差的线性主部较迭代前误差小,以导数绝对值为收敛常数线性收敛。唯一不同的是若导数值为零,此时该迭代至少二次收敛。用不动点迭代解非线性方程的核心在于将非线性方程转化为一个收敛的不动点迭代。

  例如,求解一元二次方程:$f(x)=x^2-x-2$ 时,可以分别将其转化为解等价的不动点迭代:$g(x)=x^2-2,x=g(x)$或$g(x)=\sqrt{x+2},x=g(x)$ 。但是,前者在2附近发散,只有后者收敛。

2) 实现不动点迭代算法

  不动点迭代的算法可谓没有任何技术含量,但构造不动点迭代倒是颇有些技术含量。以下为MATLAB代码,其中iteration只是用于标识迭代次数

function [ zeropt, iteration ] = fixed_point( func, seed, prec )
prev = seed;
next = func(prev);
iteration = 1;
while abs(next - prev) >= prec && iteration < 500
prev = next;
next = func(prev);
iteration = iteration + 1;
end
zeropt = next;
if iteration >= 500
error('Method fails to converge.');
end
end

  

  以上文的两个不动点函数为例:$g(x)=x^2-2, g(x)=\sqrt{x+2}$ ,均满足 $g(2)=2$ ,即2均为不动点。分别从偏离2一定距离的点开始进行试验:

func1 = @(x)x^2 - 2;
func2 = @(x)sqrt(x+2); % 命令行输入
[zero, iteration] = fixed_point(func1, 1, 0.0001)
% 命令行输出
zero = -1, iteration = 2 % 命令行输入
[zero, iteration] = fixed_point(func1, 1.9, 0.0001)
% 命令行输出
错误使用 fixed_point (line 12)
Method fails to converge. % 命令行输入
[zero, iteration] = fixed_point(func1, 2.1, 0.0001)
% 命令行输出
zero = Inf, iteration = 13 % 命令行输入
[zero, iteration] = fixed_point(func2, 1.9, 0.0001)
% 命令行输出
zero = 2.0000, iteration = 6 % 命令行输入
[zero, iteration] = fixed_point(func2, 2.1, 0.0001)
% 命令行输出
zero = 2.0000, iteration = 6

    显示出前一个函数func1由于2附近不动点迭代不收敛,会出现:跳跃到另一个零点;超过迭代步数;上溢出 的情形。而func2在2附近开始进行不动点迭代总能快速达到2.

3) 不动点迭代的迭代步复杂度、收敛速度及其他性质

  【迭代步复杂度】 一次函数值求值

  【收敛速度】 如上所述,若导数为零则至少二次收敛,若导数非零则以导数绝对值为收敛常数线性收敛。

  【优点】 1)迭代复杂度很低;2)若已知迭代函数,则实现起来没有任何技术含量,只需要不断调用函数即可。

  【缺点】 1)收敛速度很低,除非导数恰好为零,否则收敛率仅为1;2)对于一个非线性方程,必须先找到它对应的一个收敛的不动点迭代,否则一切都没用;3)必须从距离真解足够近开始迭代才有效!不过这也不只是不动点迭代的问题。

3. 牛顿法(Newton)

1) 原理

  设函数 $f(x)$ 零点的真解 $x^*$ ,即 $f(x^*)=0$,则在其一个领域内应有:$$f(x^*)\approx f(x^*-h)+f'(x^*-h)h=0$$  那么假设函数表达式已知,而又已知当前的值x在真解附近,为了估计真解的值就可以利用上式反解出 $x^*$:$$x^*=x+h=x-\frac{f(x)}{f'(x)}$$  若经过该计算,新的值距离真值更接近了,就可以把该过程写成不断迭代的形式来获得更好的精度,即:$$ x_{k+1}=x_k-\frac{f(x_k)}{f'(x_k)}$$  牛顿法的几何图像为用当前点的切线与x轴的交点估计零点的位置。

2) 牛顿法的实现

  在一般的迭代方法中,若要确定是否已经达到收敛,可以采用相邻两点间隔是否小于要求精度的方法,虽然这样的方法并不严格。在牛顿法的实现中,目前使用了待定精度(手动控制精度)的方法。另外,牛顿法中如果出现零斜率的情形(虽然在绝大多数情况下都不会出现)如何处理也是一个问题,在这里采用了“向右移动一个单位”选取下一个点的比较随意的方法。

function [ zeropt ] = nonlinNewton( func, prec, seed )
% 牛顿法求零点,输入3个参数:函数句柄func,精度prec,起始点seed;返回零点
syms f x;
f(x) = func(x); % 生成符号函数类型f
fdiff(x) = diff(f); % 生成f的符号函数类型导数fdiff
while fdiff(seed) == 0
seed = seed + 1;
end
prev = seed;
next = prev - double(f(prev)/fdiff(prev));
while abs(next - prev) >= prec % 执行迭代,直到精度符合要求
prev = next;
if fdiff(prev) == 0 % 若斜率为零则用任意算法取下一个点
next = prev + 1;
else
next = prev - double(f(prev)/fdiff(prev));
end
end
zeropt = next;
end

  同样用测试不动点迭代方法的函数(原函数)$f(x)=x^2-x-2$ 进行测试:

func = @(x)x^2-x-2;

% 命令行输入
nonlinNewton(func, 0.0001, 1)
% 命令行输出
ans = 2.0000 %命令行输入
nonlinNewton(func, 0.0001, 3)
% 命令行输出
ans = 2.0000

  

3) 牛顿法的迭代步复杂度、收敛速度及其他性质

  【迭代步复杂度】 一次原函数的求值,一次导函数的求值,以及不超过三次的四则运算。需要注意的是,牛顿法需要求导函数,并且要求可以得到导函数在任意一点的取值,这本身将耗费很大的时间代价。以上实现的算法只适用于已知解析式(符号表达式)、可以求函数的导函数的情形。

  【收敛速度】 考虑牛顿法和不动点迭代的关系,可知牛顿法的迭代公式等价于不动点迭代:$g(x)=x-f(x)/f'(x)$ 。按照不动点迭代收敛速度的分析方法,可以将 $g(x)$ 求导,结果得到 $g'(x)=f(x)f''(x)/(f'(x))^2$ ,在 $f(x)=0,f'(x)\neq 0$ 的条件下,必然有 $g'(x)=0$,因此在多数情况下牛顿法都是二次收敛的。而在零点处 $f'(x)=0$ 的情形不是别的,正是多重根的情形,该情形下问题本身的条件就属病态。

  【优点】 收敛速度比较快,对于单根均满足二次收敛。

  【缺点】 1)需要求导数,时间代价大;2)和不动点迭代类似,也需要选取合适的起点,这本身就是一件非常微妙玄学的事情。到了高维情况下,起点的选择还会显得玄学得多。

  牛顿法用一条切线进行估值。可以想见:对于凹凸性不发生变化且存在零点的函数,牛顿法从任意起点都一定收敛。另外,对于线性函数,牛顿法一步迭代立即收敛,因为这步迭代形成的切线就是函数本身了。

  最后,如果func函数只能得到它的数值输入输出而没有显式的符号表达式,如何得到可以确定它在任意一点导数值的函数呢?思路:先进行数值微分 $\rightarrow$ 转化为数值求导 $\rightarrow$ 对结果进行插值形成完整的函数。

非线性方程(组):一维非线性方程(一)二分法、不动点迭代、牛顿法 [MATLAB]的更多相关文章

  1. 非线性方程(组):MATLAB内置函数 solve, vpasolve, fsolve, fzero, roots [MATLAB]

    MATLAB函数 solve, vpasolve, fsolve, fzero, roots 功能和信息概览 求解函数 多项式型 非多项式型 一维 高维 符号 数值 算法 solve 支持,得到全部符 ...

  2. matlab实现不动点迭代、牛顿法、割线法

    不动点迭代 function xc = fpi( g, x0, tol ) x(1) = x0; i = 1; while 1 x(i + 1) = g(x(i)); if(abs(x(i+1) - ...

  3. LA 4998简单加密游戏 —— 自相似性质&&不动点迭代

    题意 输入正整数 $K_1$($K_1 \leq 50000$),找一个12为正整数 $K_2$(不能含有前导0)使得 ${K_1}^{K_2} \equiv K_2(mod \ {10}^{12}) ...

  4. 非线性方程(组):一维非线性方程(二)插值迭代方法 [MATLAB]

    一般而言,方程没有能够普遍求解的silver bullet,但是有几类方程的求解方法已经非常清晰确凿了,比如线性方程.二次方程或一次分式.一次方程可以直接通过四则运算反解出答案,二次方程的求根公式也给 ...

  5. 2012年蓝桥杯省赛A组c++第1题(xy迭代增殖)

    /* 微生物增殖 题目: 假设有两种微生物 X 和 Y X出生后每隔3分钟分裂一次(数目加倍),Y出生后每隔2分钟分裂一次(数目加倍). 一个新出生的X,半分钟之后吃掉1个Y,并且,从此开始,每隔1分 ...

  6. 2 jmeter常用功能介绍-测试计划、线程组

    1.测试计划测试用来描述一个性能测试,所有内容都是基于这个测试计划的. (1)User Defined Variables:设置用户全局变量.一般添加一些系统常用的配置.如果测试过程中想切换环境,切换 ...

  7. Jmeter系列(10)- 阶梯加压线程组Stepping Thread Group详解

    如果你想从头学习Jmeter,可以看看这个系列的文章哦 https://www.cnblogs.com/poloyy/category/1746599.html 前言 Stepping Thread ...

  8. 转 2 jmeter常用功能介绍-测试计划、线程组

    2 jmeter常用功能介绍-测试计划.线程组   1.测试计划测试用来描述一个性能测试,所有内容都是基于这个测试计划的. (1)User Defined Variables:设置用户全局变量.一般添 ...

  9. 数值分析:幂迭代和PageRank算法

    1. 幂迭代算法(简称幂法) (1) 占优特征值和占优特征向量 已知方阵\(\bm{A} \in \R^{n \times n}\), \(\bm{A}\)的占优特征值是量级比\(\bm{A}\)所有 ...

随机推荐

  1. POJ 1946 Cow Cycling(抽象背包, 多阶段DP)

    Description The cow bicycling team consists of N (1 <= N <= 20) cyclists. They wish to determi ...

  2. resolution will not be reattempted until the update interval of nexus has elapsed or updates are forced

    Maven在执行中报错: - Failure to transfer org.slf4j:slf4j-api:jar:1.7.24 from http://localhost:8081/nexus/c ...

  3. express——crud

    使用express框架做一个简单的增删改查demo,先上效果图: 1.使用webstrom新建一个express项目,建好的项目文件是这样的: 2.直接上代码,方便学习db.js /** * Crea ...

  4. HTML5 ShadowDOM & CustomElements

    Web组件由四部分组成 Template Shadow DOM (Chrome Opera支持) Custom Elements Packaging Shadow DOM 组成 Shadow DOM可 ...

  5. synchronized将任意对象作为对象监视器

    多个线程调用同一个对象中的不同名称的synchronized同步方法或synchronized(this)同步代码块时,调用的效果就是按顺序执行,也就是同步的,阻塞的.这说明synchronized同 ...

  6. ACM中Java高效输入输出封装

    来自互联网 : 既高效又好用才是王道! import java.io.IOException; import java.io.FileInputStream; import java.io.Input ...

  7. ubuntu解压命令

    .tar.gz 解压缩文件:  tar zxvf a.tar.gz 压缩文件命令:tar -zcvf test3.tar.gz  test1 test2 此命令是将两个文件夹 或文件同时压缩到一个文件 ...

  8. Windows Phone 自定义一个启动画面

    1.新建一个UserControl <UserControl x:Class="LoadingPage.PopupSplash" xmlns="http://sch ...

  9. WCF(五) 深入理解绑定

    适用于本机WCF-WCF交互性能最佳的绑定: 允许跨主机,但只能用于部署同一台主机上,不能访问命名管道 netNamePipeBinding总结 一 WCF与SOA SOA是一种通过为所有软件提供服务 ...

  10. 问答项目---用户注册的那些事儿(JS验证)

    做注册的时候,由于每一个页面都有都要可以注册,可以把注册方法写到一个公用的方法里去,其他方法继承这个方法: 简单注册JS示例: <script type='text/javascript'> ...