这是代码:
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没有完成一个小时。我使用错误的数值方法吗?
答案 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
是双精度的(将其分配为sym
或vpa
,您需要更高的精度:
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
我检查过,对于您的问题并使用默认容差,结果T
在eps
解决方案的机器epsilon(numeric::fsolve'
)的几倍之内。