tl; dr:在将符号表达式转换为matlabFunction
的函数句柄时,我发现完全失去了准确性。我想知道是否有办法改善转换以避免精度的损失。
我有一个符号变量x
,其中1 <= x && x <= 2
成立:
syms x real
assumeAlso(1 <= x & x <= 2);
我在该变量中有许多计算机生成的,冗长的符号表达式。其中一个看起来像这样:
expression = ( ...
1015424780204960143215273323910078528628754663952913658657288835138029704791686717561885487746105223164496264397062144000 ...
*( ...
60345244216851610523130575942127473698515638085026410114070496399315754724985170479034760688327679099512793302302720*2^(1/2) ...
- 85341062796188128379389251264141456937242003828816791711306294886439805159655912635773490018204138847163921224639041 ...
)*(x - 2)^2 ...
) ...
/31504288346872372712061562812941419427167561153216213605146864117586323331155800294021400857537041202039565879856190821729945216935526707438840242294801134287960934949194864204307116208568439380511702602881;
编辑你必须用它构建(粘贴上面的内容会使expression
成为常量0)
expression = sym('(1015424780204960143215273323910078528628754663952913658657288835138029704791686717561885487746105223164496264397062144000*(60345244216851610523130575942127473698515638085026410114070496399315754724985170479034760688327679099512793302302720*2^(1/2) - 85341062796188128379389251264141456937242003828816791711306294886439805159655912635773490018204138847163921224639041)*(x - 2)^2)/31504288346872372712061562812941419427167561153216213605146864117586323331155800294021400857537041202039565879856190821729945216935526707438840242294801134287960934949194864204307116208568439380511702602881');
调用double(subs(expression, x, 1))
将此表达式计算为大约-5.9492e+03
,没有任何问题,这实际上是正确的值。但是,评估花费的时间太长,在我的应用程序中是一个巨大的(或相当小的?)瓶颈。这就是为什么我打算将表达式转换为一个匿名函数,它运行双精度并且速度更快,如下所示:
evaluator = matlabFunction(expression, 'Vars', x);
结果是
@(x) (sqrt(2.0).*6.034524421685161e115-8.534106279618813e115) ...
.*(x-2.0).^2.*3.223131940086397e-86
我过去在这种方法上取得了很大的成功。不幸的是,在这种情况下,对于 x 的任何值,evaluator(x)
的计算结果为0,因为第一行恰好为零。显然,这与双打有限数量的有效数字有关。
有办法解决这个问题吗?我可以告诉MATLAB考虑x
的范围,以便它能找到更好的常量表示吗?
答案 0 :(得分:0)
问题可以通过variable-precision arithmetic解决:
>> expr = vpa(expression)
expr =
-5949.2156936801140978790460880789*(x - 2.0)^2
将其转换为函数
>> func =
function_handle with value:
@(x)(x-2.0).^2.*-5.949215693680114e3
然后评估
>> func(1)
ans =
-5.9492e+03