二分法是用来求函数零点的方法,如果函数可导,那么函数的一阶导的零点就是原函数的极值点。但是如果原函数没有极值点,比如一个单调函数,其最值在某一端点。这样求导后就不满足二分法求零点的条件。
1.二分法算法步骤:
|
1.二分法代码MALTAB实现:
测试函数:
clc,clear
f = @(x) 2*x.^2 - x - 1; %原函数
df = @(x)4*x - 1; %一阶导数
a = -3;
b = 0.25;
epsilon = 1e-4;
tic
res = binarySearch(df,a,b,epsilon)
toc
% 符号函数实现
func = sym('2*x^2 - x - 1');
tic
res1 = binarySearch1(func,a,b,epsilon)
toc
传函数句柄方式:
% binarySearch 二分法
% - 优点:计算量少,而且总能收敛到一个局部极小点,不需要计算导数
% - 缺点:收敛速度慢,需要函数可导
% Inputs:
% - df 函数的一阶导数
% - a 搜索区间下限
% - b 搜索区间下限
% - epsilon 精度:用区间长度衡量
% Outputs:
% -res 搜索结果
function res = binarySearch(df,a,b,epsilon)
% 检查输入
if df(a)*df(b) > 0
display('BinarySearch: 二分法区间端点值同号……');
return;
end
%初始化
x1 = a;
x2 = b;
mean = 0.5*(x1 + x2);
%计算
while(true)
% state = [x1 x2]
if(abs(x1-x2)<epsilon) break; end
if(df(x1)*df(mean) > 0)
x1 = mean;
elseif(df(x1)*df(mean) < 0)
x2 = mean;
elseif(df(x1)*df(mean) == 0)
res = mean; break;
end
mean = 0.5*(x1 + x2);
end
res = 0.5*(x1 + x2);
end
传符号函数方式:
% binarySearch 二分法
% - 优点:计算量少,而且总能收敛到一个局部极小点,不需要计算导数
% - 缺点:收敛速度慢
% Inputs:
% - func 原函数的符号函数
% - a 搜索区间下限
% - b 搜索区间下限
% - epsilon 精度:用区间长度衡量
% Outputs:
% -res 搜索结果
function res = binarySearch1(func,a,b,epsilon)
df = diff(func);
% 检查输入
if subs(df,a)*subs(df,b) > 0
display('BinarySearch: 二分法区间端点值同号……');
return;
end
%初始化
x1 = a;
x2 = b;
mean = 0.5*(x1 + x2);
%计算
while(true)
% state = [x1 x2]
if(abs(x1-x2)<epsilon) break; end
if(subs(df,x1)*subs(df,mean) > 0)
x1 = mean;
elseif(subs(df,x1)*subs(df,mean) < 0)
x2 = mean;
elseif(subs(df,x1)*subs(df,mean) == 0)
res = mean; break;
end
mean = 0.5*(x1 + x2);
end
res = 0.5*(x1 + x2);
end
结果如下图(函数句柄的方式比符号函数方式计算速度快很多):