永远不要假设像 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 能够返回正确的前 100 位 pi,即使将 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 值,存储在双精度数中,然后将其转换为 HPF 数。
>> hpf(pi,100)
ans =
3.141592653589793115997963468544185161590576171875
>> hpf('pi',100)
ans =
3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068
>> hpf('pi',100) - hpf(pi,100)
ans =
0.0000000000000001224646799147353177226065932275001058209749445923078164062862089986280348253421170679821480800000000
很明显,MATLAB 能够将 pi 识别为不仅仅是将传入的双精度值。
编辑2:
事实上,一点游戏告诉我这里发生了什么。VPA 是一个棘手的问题,而不是解析器。考虑分数 7/13。如果我们将其构建为 double,然后打印出存储在其全部荣耀中的浮点值,我们会发现它并不完全准确。这正如预期的那样。
>> sprintf('%.100f',7/13)
ans =
0.5384615384615384359179302009579259902238845825195312500000000000000000000000000000000000000000000000
7/13 是重复的十进制值。以下是正确的数字:
>> vpa('7/13',100)
ans =
0.5384615384615384615384615384615384615384615384615384615384615384615384615384615384615384615384615385
现在,假设我们尝试创建相同的数字。在这里,我会以双精度形式传递 7/13,但我会在底部的十进制数字中出错
>> 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) 被计算为双精度,但随后 vpa 将其视为与 sqrt(2)/2 的双精度版本相同的数字。
当然要小心。例如,vpa 不够聪明,无法捕捉到 pi 的这种简单变化。
>> vpa(pi + 1,100)
ans =
4.141592653589793115997963468544185161590576171875
>> vpa(pi,100)
ans =
3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068