昨天在《MATLAB算法の二分法》中给大家介绍二分法的matlab编程实现,但是该编程方式并没有最充分地利用matlab强大的矢量化计算功能。为了实现矢量化计算,作者对二分法算法本身也做了一些改进 (注:此方法未曾参考过任何人的文章或者书籍)。

同样先给出二分法如下定义:对于在区间[a,b]上连续且单调的函数f(x),若满足条件f(a)*f(b)<0,则函数f(x)在此区间上必存在根。通过不断把此区间一分为二,使区间的两个端点逐步逼近零点,进而得到零点准确值或近似值的方法。

根据以上定义,既然可以在区间[a,b]上二分,当然也可以在区间上n等分,又因函数f(x)在区间[a,b]上是单调的,计算出各个等分点的函数值,将函数值正负值发生改变处的两个等分点作为新的区间[na,nb],继续将此区间n等分,重复上面步骤,将区间差绝对值Δ=|na-nb|作为精度控制标识,达到精度后,取na与nb的平均值作为函数的根。

具体实现步骤:

1、分别计算f(a),f(b)的函数值,验证f(a)*f(b)是否小于0,若小于0则说明在区间[a,b]上存在根。

2、n等分区间[a,b],并计算各等分点的函数值。

3、查找函数值中是否存在等于的点,如存在则该点即为所寻之根,若不存在则找出函数值正负发生变化的两个位置,将前者作为a,后者作为b。

4、通过比较区间差绝对值与计算精度e的大小来判断是否达到预设条件,若|a-b|<e,则得到根的近似值(a+b)/2,否则重复2至4步骤。

改进版二分法matlab源代码

问题定义:求函数f(x) = 3*x.^3-9*x.^2+5.6*x-7.5在区间[2,3]的根,计算精度为10^-6.

clc;clear;close all;

% 定义区间[2,3]

x = 2:0.1:3;

% 定义参考y值,即y=0的直线

ty = zeros(1,length(x));

% 定义在区间[2,3]上单调的函数fun

fun = @(x) 3*x.^3-9*x.^2+5.6*x-7.5;

y = fun(x);

% 定义划分区间的分数

divQJ = 10000;

% 绘制示意图

plot(x,y,'b.-',x,ty,'r--','LineWidth',3.5);

xlabel('x轴');

ylabel('y轴');

title('二分法寻根测试');

% 定义计算精度ep和临时变量tmp

% 对于不知道循环次数的,用whlie来实现

if fun(a)*fun(b) < 0

while(tmp>ep)

% 等分区间

tX = linspace(a,b,divQJ);

% 计算函数值

tY = fun(tX);

loc = find(tY == 0);

if isempty(loc)

% 找到函数值正负变化的位置

locM = find(tY<0);

locP = find(tY>0);

% 定义新区间

if tY(1)<0

a = tX(locM(end));

b = tX(locP(1));

tmp = abs(a-b);

a = tX(locP(end));

b = tX(locM(1));

tmp = abs(a-b);

% 计算近似根

mid = (a+b)/2;

mid = tX(loc);

disp('此区间不存在根!!!');

JG = fun(mid);

disp('**********************二分法改进版**********************')

disp(['在区间[2,3]的近似解为',char(vpa(mid,8)),'; 在区间[2,3]的函数值为',num2str(JG)]);

% 绘制近似交点

plot(mid,JG,'r.','MarkerSize',50);

disp(['程序运行次数为:',num2str(k),' (次)']);

运行结果对比:

从上图可以看出,不论是计算精度还是运行次数,改进后的二分法都表现得更加出色。也希望大家在平常编程中多多使用matlab矢量化计算来提高自己程序的运行效率。