首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >MatLab -变精度算术

MatLab -变精度算术
EN

Stack Overflow用户
提问于 2012-06-04 02:47:18
回答 4查看 5.2K关注 0票数 1

我有一个简短的问题,关于在MatLab中可以用来计算符号表达式的vpa命令。

我的课本上是这样说的:

在对数字使用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')时相同的答案。

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

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2012-06-04 02:51:46

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

代码语言:javascript
复制
  vpa(sqrt(5)/pi)
= vpa(0.7117625434171772)

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

票数 5
EN

Stack Overflow用户

发布于 2012-06-04 04:25:24

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

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

代码语言:javascript
复制
sin(pi/4) == sqrt(2)/2

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

代码语言:javascript
复制
>> 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)?

代码语言:javascript
复制
>> 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。

代码语言:javascript
复制
>> DefaultNumberOfDigits 100
>> (sqrt(hpf(3)) - 1)*sqrt(hpf(2))/4
ans =
0.2588190451025207623488988376240483283490689013199305138140032073150569747488019969223679746942496655

关键是,不要相信解析器会在这里拯救你。

编辑:作为对Amro评论的测试,我恭敬地声明MATLAB在这里正在做一些有趣的事情。确保vpa能够返回正确的pi的前100位,即使将pi作为双精度数字传递时也是如此。由于圆周率(作为双精度)不是正确的过去的第16位小数,有一些可疑的事情正在发生。

代码语言:javascript
复制
>> vpa(pi,100)
ans =
3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068

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

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

作为对这一事实的测试,让我们看看HPF发现了什么。HPF实际上采用存储在双精度型中的IEEE754值,然后将其转换为HPF数字。

代码语言:javascript
复制
>> hpf(pi,100)
ans =
3.141592653589793115997963468544185161590576171875

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

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

很明显,MATLAB能够识别π,而不仅仅是传递给它的双精度值。

Edit2:

事实上,稍微玩玩一下就能告诉我这里发生了什么。VPA是一个棘手的问题,而不是解析器。考虑分数7/13。如果我们将其构建为双精度,然后打印出存储在其完全荣耀中的浮点值,我们看到它并不是真正精确的。这和预期的一样。

代码语言:javascript
复制
>> sprintf('%.100f',7/13)
ans =
0.5384615384615384359179302009579259902238845825195312500000000000000000000000000000000000000000000000

7/13是一个重复的十进制值。以下是正确的数字:

代码语言:javascript
复制
>> vpa('7/13',100)
ans =
0.5384615384615384615384615384615384615384615384615384615384615384615384615384615384615384615384615385

现在,假设我们尝试创建相同的数字。在这里,我将传递7/13作为双精度,但我会在小数点后数位中犯错误

代码语言:javascript
复制
>> sprintf('%.100f',0.538461538461538461777777777)
ans =
0.5384615384615384359179302009579259902238845825195312500000000000000000000000000000000000000000000000

在这里,我们看到vpa捕获并纠正了我犯下的“错误”,认识到我传入的内容实际上与我在7/13传入时的值相同。

代码语言:javascript
复制
>> vpa(0.538461538461538461777777777,100)
ans =
0.5384615384615384615384615384615384615384615384615384615384615384615384615384615384615384615384615385

当然,如果我以字符串的形式传入值,那么vpa就会出错。

代码语言:javascript
复制
>> vpa('0.538461538461538461777777777',100)
ans =
0.538461538461538461777777777

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

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

代码语言:javascript
复制
>> vpa(pi + 1,100)
ans =
4.141592653589793115997963468544185161590576171875

>> vpa(pi,100)
ans =
3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068
票数 11
EN

Stack Overflow用户

发布于 2012-06-04 02:55:45

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

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

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10872933

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档