我使用错误的数值方法吗?

时间:2014-02-14 17:45:41

标签: performance matlab numeric symbolic-math

这是代码:

f = dsolve('D3y+12*Dy+y = 0 ,y(2) = 1 ,Dy(2) = 1, D2y(2) = -1');
feval(symengine, 'numeric::solve',strcat(char(f),'=1'),'t=-4..16','AllRealRoots')

如果我删除'AllRealRoots'选项,它可以快速找到解决方案,但是当我启用选项时,Matlab没有完成一个小时。我使用错误的数值方法吗?

1 个答案:

答案 0 :(得分:0)

首先,直接来自numeric::solve的文档:

  

如果eqs是非多项式/非有理方程或包含这样的方程的集合或列表,则方程式和适当的可选参数将传递给数值解算器numeric :: fsolve。

因此,由于等式f是非多项式,您应该直接调用numeric::fsolve。但是,即使使用'MultiSolutions',它也无法在您的范围内返回多个根(可能是一个错误? - 我正在使用R2013b)。解决方法是调用numeric::realroots来获取您范围内每个区域实根的边界,然后单独解决它们:

f = dsolve('D3y+12*Dy+y = 0 ,y(2) = 1 ,Dy(2) = 1, D2y(2) = -1');
r = feval(symengine, 'numeric::realroots', f==1, 't = -4 .. 16');

num_roots = numel(r);
T = zeros(num_roots,1); % Wrap in sym or vpa for higher precision output
syms t;
for i = 1:num_roots
    bnds = r(i);
    ri = feval(symengine, '_range', bnds(1), bnds(2));
    s = feval(symengine, 'numeric::fsolve', f==1, t==ri);
    T(i) = feval(symengine, 'rhs', s(1));
end

结果解决方案向量T是双精度的(将其分配为symvpa,您需要更高的精度:

T =

  -0.663159371123072
   0.034848320470578
   0.999047064621451
   2.000000000000000
   2.695929753727520
   3.933983894260340
   4.405822476913172
   5.868112290810963
   6.108685019679461

如果您可以一次性弄清楚如何干净地将for的输出传递给'numeric::realroots',那么您可以移除'numeric::fsolve'循环(这可能是可行的,但可能需要除非你聪明,否则将stuf转换为字符串。

另一种(可能更快)的方法是在绑定所有根之后切换到使用数字(浮点)函数fzero作为后半部分:

f = dsolve('D3y+12*Dy+y = 0 ,y(2) = 1 ,Dy(2) = 1, D2y(2) = -1');
r = feval(symengine, 'numeric::realroots', f==1, 't = -4 .. 16');

num_roots = numel(r);
T = zeros(num_roots,1);
g = matlabFunction(f-1); % Create anonymous function from f
for i = 1:num_roots
    bnds = double(r(i));
    T(i) = fzero(g,bnds);
end

我检查过,对于您的问题并使用默认容差,结果Teps解决方案的机器epsilon(numeric::fsolve')的几倍之内。