MatLab - 变量精度算术

Kri*_*ian 1 matlab numbers arbitrary-precision

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

我的教科书说明如下:

"使用诸如sqrt数字之类的函数时需要小心,默认情况下会产生双精度浮点数.您需要将此类输入vpa作为符号字符串传递给正确的评估:vpa('sqrt(5)/pi')."

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

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

小智 10

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

但是,它似乎在这里是正确的.例如,我们知道这一点

sin(pi/4) == sqrt(2)/2
Run Code Online (Sandbox Code Playgroud)

让我们测试一下结果.我将使用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
Run Code Online (Sandbox Code Playgroud)

因此,我的猜测是解析器已将输入识别为符号工具箱可以更准确地计算的内容.正如我之前所说,但要小心.什么是罪(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
Run Code Online (Sandbox Code Playgroud)

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

>> DefaultNumberOfDigits 100
>> (sqrt(hpf(3)) - 1)*sqrt(hpf(2))/4
ans =
0.2588190451025207623488988376240483283490689013199305138140032073150569747488019969223679746942496655
Run Code Online (Sandbox Code Playgroud)

关键是,不要相信解析器在这里保存你.

编辑:作为对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
Run Code Online (Sandbox Code Playgroud)

作为对这一事实的考验,让我们看看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
Run Code Online (Sandbox Code Playgroud)

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

EDIT2:

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

>> sprintf('%.100f',7/13)
ans =
0.5384615384615384359179302009579259902238845825195312500000000000000000000000000000000000000000000000
Run Code Online (Sandbox Code Playgroud)

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

>> vpa('7/13',100)
ans =
0.5384615384615384615384615384615384615384615384615384615384615384615384615384615384615384615384615385
Run Code Online (Sandbox Code Playgroud)

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

>> sprintf('%.100f',0.538461538461538461777777777)
ans =
0.5384615384615384359179302009579259902238845825195312500000000000000000000000000000000000000000000000
Run Code Online (Sandbox Code Playgroud)

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

>> vpa(0.538461538461538461777777777,100)
ans =
0.5384615384615384615384615384615384615384615384615384615384615384615384615384615384615384615384615385
Run Code Online (Sandbox Code Playgroud)

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

>> vpa('0.538461538461538461777777777',100)
ans =
0.538461538461538461777777777
Run Code Online (Sandbox Code Playgroud)

这解释了为什么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
Run Code Online (Sandbox Code Playgroud)


Ble*_*der 5

我不是专家MatLab的,但不包括引号,你传递的结果sqrt(5)/pivpa()

  vpa(sqrt(5)/pi)
= vpa(0.7117625434171772)
Run Code Online (Sandbox Code Playgroud)

使用引号,您将表达式 sqrt(5)/pi(未计算且为精确形式)传递给vpa(),然后告诉 MatLab 以sqrt(5)/pi可变精度进行计算。