MatLab - 变量精度算术

时间:2012-06-03 18:47:18

标签: matlab numbers arbitrary-precision

我有一个关于vpa命令的简短问题,可用于评估MatLab中的符号表达式。

我的教科书说明如下:

“在数字上使用sqrt等函数时需要注意,默认情况下会产生双精度浮点数。您需要将此类输入传递给vpa as用于正确评估的符号字符串:vpa('sqrt(5)/pi')。“

我不太明白这里的行话。为什么对于大多数输入我得到完全相同的答案我是否输入vpa(input)vpa('input'),而不是平方根?例如,如果我输入vpa(sin(pi/4))vpa('sin(pi/4)'),我会得到完全相同的答案,但如果我输入上面的问题为vpa(sqrt(5)/pi),我得到的答案与我的答案不同输入vpa('sqrt(5)/pi')

如果有人能够比我上面的书更详细地解释这一点,我将非常感激!

4 个答案:

答案 0 :(得分:10)

永远不要假设像vpa(sin(pi / 4))这样的数字精确到完全精度,因为MATLAB通常会使用浮点运算来计算vpa调用内的数字,因此只能精确到大约16位数。

然而,它似乎在这里是正确的。例如,我们知道

sin(pi/4) == sqrt(2)/2

让我们测试一下结果。我将使用100位数的精度,比较vpa和我自己的HPF工具。

>> vpa(sin(pi/4),100)
ans =
0.7071067811865475244008443621048490392848359376884740365883398689953662392310535194251937671638207864

>> vpa(sqrt(sym(2))/2,100)
ans =
0.7071067811865475244008443621048490392848359376884740365883398689953662392310535194251937671638207864

>> sqrt(hpf(2,100))/2
ans =
0.7071067811865475244008443621048490392848359376884740365883398689953662392310535194251937671638207864

>> sin(hpf('pi',100)/4)
ans =
0.7071067811865475244008443621048490392848359376884740365883398689953662392310535194251937671638207864

所以,我的猜测是解析器已将输入识别为符号工具箱可以更准确地计算的内容。正如我之前所说,但要小心。什么是罪(pi / 12)?

>> vpa(sin(pi/12),100)
ans =
0.25881904510252073947640383266843855381011962890625

>> vpa('sin(pi/12)',100)
ans =
0.2588190451025207623488988376240483283490689013199305138140032073150569747488019969223679746942496655

>> vpa(sin(sym('pi')/12),100)
ans =
0.2588190451025207623488988376240483283490689013199305138140032073150569747488019969223679746942496655

>> sin(hpf('pi',100)/12)
ans =
0.2588190451025207623488988376240483283490689013199305138140032073150569747488019969223679746942496655

在第一种情况下,解析器没有保存我们。在其他人中,我强迫MATLAB计算正确的值。事实上,一些努力会给我们sin(pi / 12)的价值,如sqrt(2)*(sqrt(3) - 1)/ 4。

>> DefaultNumberOfDigits 100
>> (sqrt(hpf(3)) - 1)*sqrt(hpf(2))/4
ans =
0.2588190451025207623488988376240483283490689013199305138140032073150569747488019969223679746942496655

重点是,不要相信解析器会把你保存在这里。

编辑:作为对Amro评论的考验,我恭敬地说MATLAB正在做一些有趣的事情。看到vpa能够返回pi的正确前100位数,即使将pi作为双精度数传递也是如此。因为pi(作为一个双精度数)在第16个十进制数字之后是不正确的,所以有一些可疑的东西。

>> vpa(pi,100)
ans =
3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068

>> vpa('pi',100)
ans =
3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068

vpa('pi',100) - vpa(pi,100)
ans =
0.0

作为对这一事实的考验,让我们看看HPF发现了什么。 HPF实际上采用IEEE 754值,如存储在double中,然后将其转换为HPF编号。

>> hpf(pi,100)
ans =
3.141592653589793115997963468544185161590576171875

>> hpf('pi',100)
ans =
3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068

>> hpf('pi',100) - hpf(pi,100)
ans =
0.0000000000000001224646799147353177226065932275001058209749445923078164062862089986280348253421170679821480800000000

很明显,MATLAB能够将pi识别为不仅仅是传递的双精度值。

Edit2:

事实上,一些游戏告诉我这里发生了什么。 VPA是棘手的,而不是解析器。考虑7/13分数。如果我们将它构建为double,那么打印出存储在其完整荣耀中的浮点值,我们认为它并不是真正准确的。这是预期的。

>> sprintf('%.100f',7/13)
ans =
0.5384615384615384359179302009579259902238845825195312500000000000000000000000000000000000000000000000

7/13是重复的十进制值。这是正确的数字:

>> vpa('7/13',100)
ans =
0.5384615384615384615384615384615384615384615384615384615384615384615384615384615384615384615384615385

现在,假设我们尝试创建相同的数字。在这里我将以7/13的速度传递asa double,但我会在底部的十进制数字中输入错误

>> sprintf('%.100f',0.538461538461538461777777777)
ans =
0.5384615384615384359179302009579259902238845825195312500000000000000000000000000000000000000000000000

在这里,我们看到vpa捕获并纠正了我所做的'错误',认识到我传入的内容实际上与我在7/13时传递的内容完全相同。

>> vpa(0.538461538461538461777777777,100)
ans =
0.5384615384615384615384615384615384615384615384615384615384615384615384615384615384615384615384615385

当然,如果我将值作为字符串传递,那么vpa就会出错。

>> vpa('0.538461538461538461777777777',100)
ans =
0.538461538461538461777777777

这解释了为什么vpa能够捕获并正确计算vpa(sin(pi / 4),100),达到所要求的全部精度。 sin(pi / 4)计算为double,但是vpa将其视为与sqrt(2)/ 2的双精度版本相同的数字。

当然要小心。例如,vpa不够智能,无法捕捉pi的这种简单转变。

>> vpa(pi + 1,100)
ans =
4.141592653589793115997963468544185161590576171875

>> vpa(pi,100)
ans =
3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068

答案 1 :(得分:4)

我不是MatLab专家,但没有引号,您将sqrt(5)/pi结果传递给vpa()

  vpa(sqrt(5)/pi)
= vpa(0.7117625434171772)

使用引号,您将表达式 sqrt(5)/pi(未评估并以精确格式)传递到vpa(),然后告诉MatLab使用变量计算sqrt(5)/pi精度。

答案 2 :(得分:1)

如果你得到了完全相同的答案,那么你就不需要变量精度算术了。

但是,sin(pi/4)应该是sqrt(2)/2,这是不合理的。你不应该从不同的精度得到完全相同的答案。也许你应该检查你如何显示(和四舍五入)结果。

答案 3 :(得分:1)

关于numeric to symbolic转换的最新文档有答案。

  

sym尝试纠正浮点输入中的舍入误差   返回确切的符号形式。具体来说,sym纠正了四舍五入   数字输入中与形式p / q,pπ/ q,(p / q)^(1/2),2 ^ q匹配的错误,   和10 ^ q,其中p和q是中等大小的整数。

因此,sin(pi/4)2^(1/2)/2(1/2)^(1/2),因此vpa命令可识别它。但是,根据文档,sqrt(5)/pi不是公认的输入表单。