求根:划界法

导论

        本文主要介绍单变量非线性方程求根的划界法。采用的例子为典型的蹦极运动员模型,模型背景不再介绍,具体题目为求解使得以下方程的成立的m:

f(m)=\sqrt{\frac{gm}{c_d}}tanh(\sqrt{\frac{gc_d}{m}}t)-v

其中g,cd,t,v均已知。

        划界法一个典型的特定是,在进行算法之前,需要给出一个区间,在此区间之内函数连续且存在且只存在一个根。通常通过画图寻找满足的区间。本例中函数图形如下:

易知,在[40, 200]区间内存在根。

二分法

        二分法的思想是:计算区间中点处的函数值,函数值与哪个区间端点处的函数值具有相同的符号,则使用中点取代此端点,形成新的区间,如此不断迭代。迭代的终止条件为:

|\varepsilon_a|=|\frac{x^{new}-x^{old}}{x^{new}}|<\varepsilon_s

clear
clc

fm = @(m, cd, t, v) sqrt(9.81.*m./cd).*tanh(sqrt(9.81.*cd./m)*t) - v;
m = 50:0.1:200;
y = fm(m, 0.25, 4,36);
plot(m, y)
grid on
hold on
[root, fx, ea, iter] = bisect(@(m) fm(m, 0.25, 4, 36), 40, 200);

function [root, fx, ea, iter] = bisect(func, xl, xu, es, maxit, varargin)
% 使用二分法寻根
% 输入参数:
% func:函数名称
% xl,xu:区间上下界
% es:期望误差
% macit:最大迭代次数
% p1,p2,...:函数func的额外参数
% 输出参数:
% root:根
% fx:在根root处的函数值
% ea:实际相对误差
% iter:迭代次数
if nargin<3, error('至少输入三个参数:函数名,区间下界,区间上界'),end
test = func(xl, varargin{:})*func(xu, varargin{:});
if test>0, error('区间上下界处符号没有改变'), end
if nargin<4||isempty(es), es = 0.0001; end
if nargin<5||isempty(maxit), maxit = 50; end
iter = 0; xr = xl; ea = 100;
while(1)
    xrold = xr;
    xr = (xl+xu)/2;
    iter = iter+1;
    if xr~=0, ea = abs((xr - xrold)/xr) * 100; end
    test = func(xl, varargin{:})*func(xr, varargin{:});
    if test<0
        xu = xr;
    elseif test>0
        xl = xr;
    else
        ea = 0;
    end
    if ea<=es || iter>maxit, break, end
    plot(xr, func(xr, varargin{:}),'*')
    hold on
end
root = xr; fx = func(xr, varargin{:});
end

可以看出,迭代21次结束循环,求得的解为142.7377。

关于二分法的误差分析,此处不再详细展开,只介绍一些与二分法求根相关的结论:

  • 在二分法中采用近似误差作为迭代终止条件,但二分法中近似误差一定小于真误差,因此二分法得出的解在误差要求方面一定满足要求。
  • 二分法达到某个绝对误差所需的迭代次数可以预先得到。

试位法

        试位法又称为线性插值法,其思想是使用通过区间两端的直线与x轴的交点作为新的估计值。试位公式为:

x_r = x_u-\frac{f(x_u)(x_l-x_u)}{f(x_l)-f(x_u)}

试位法与二分法相比,除了计算x新值的公式不同之外其余步骤完全相同。

clear
clc

fm = @(m, cd, t, v) sqrt(9.81.*m./cd).*tanh(sqrt(9.81.*cd./m)*t) - v;
m = 50:0.1:200;
y = fm(m, 0.25, 4,36);
plot(m, y)
grid on
hold on
[root, fx, ea, iter] = shiwei(@(m) fm(m, 0.25, 4, 36), 40, 200);

function [root, fx, ea, iter] = shiwei(func, xl, xu, es, maxit, varargin)
% 使用试位法寻根
% 输入参数:
% func:函数名称
% xl,xu:区间上下界
% es:期望误差
% macit:最大迭代次数
% p1,p2,...:函数func的额外参数
% 输出参数:
% root:根
% fx:在根root处的函数值
% ea:实际相对误差
% iter:迭代次数
if nargin<3, error('至少输入三个参数:函数名,区间下界,区间上界'),end
test = func(xl, varargin{:})*func(xu, varargin{:});
if test>0, error('区间上下界处符号没有改变'), end
if nargin<4||isempty(es), es = 0.0001; end
if nargin<5||isempty(maxit), maxit = 50; end
iter = 0; xr = xl; ea = 100;
while(1)
    xrold = xr;
    fl = func(xl, varargin{:});
    fu = func(xu, varargin{:});
    xr = xu - (fu*(xl-xu) / (fl-fu));
    iter = iter+1;
    if xr~=0, ea = abs((xr - xrold)/xr) * 100; end
    test = func(xl, varargin{:})*func(xr, varargin{:});
    if test<0
        xu = xr;
    elseif test>0
        xl = xr;
    else
        ea = 0;
    end
    if ea<=es || iter>maxit, break, end
    plot(xr, func(xr, varargin{:}),'*')
    hold on
end
root = xr; fx = func(xr, varargin{:});
end

试位法迭代29次得到了与二分法几乎相同的结果。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值