1

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

我的教科书是这样说的:

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

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

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

4

4 回答 4

11

永远不要假设像 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
于 2012-06-03T20:25:24.393 回答
5

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

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

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

于 2012-06-03T18:51:45.610 回答
1

如果您得到完全相同的答案,则不需要可变精度算术开始。

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

于 2012-06-03T18:55:45.043 回答
1

关于数字到符号转换的最新文档有答案。

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

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

于 2016-01-25T13:49:40.540 回答