Labfans是一个针对大学生、工程师和科研工作者的技术社区。 | 论坛首页 | 联系我们(Contact Us) |
![]() |
|
![]() |
#1 |
高级会员
注册日期: 2019-11-21
帖子: 3,006
声望力: 66 ![]() |
![]()
这个问题是我进一步调查后发现的奇怪问题 。
我一直都理解默认情况下MATLAB变量是双精度的。因此,如果我要进行一些操作,例如声明一个小数点后20位数字的变量: >> num = 2.71828182845904553488; >> class(num) % Display the variable type ans = double 我希望最后4位数字被忽略,因为浮点相对精度约为10 -16 : >> eps(num) ans = 4.440892098500626e-016 如果我尝试显示小数点后的数字超过16位(使用fprintf或sprintf ),那么我会看到: >> fprintf('%0.20f\n', num) 2.71828182845904550000 >> sprintf('%0.20f', num) ans = 2.71828182845904550000 换句话说,数字17到20均为0。 但是,当我将num传递给Symbolic Toolbox中的变量精度算术函数时,事情变得很奇怪,告诉它使用21位精度表示数字: >> vpa(num, 21) ans = 2.71828182845904553488 什么?!那些后四位数字又出现了!当我输入的原始数字存储为双精度变量num时,它们不应该丢失吗?由于num是当它被传递给一个双精度变量vpa ,怎么vpa知道它们是什么? 我对发生的事情的最佳猜测是,MATLAB在内部以比双精度更高的精度表示num ,因为我将其初始化为比双精度变量可以处理的小数点后数字更多的数字。这真的是发生了什么,还是发生了其他事情? 奖励:如果您还没有上述偏头痛的话,这是另外一个困惑的来源... >> num = 2.71828182845904553488; % Declare with 20 digits past the decimal >> num = 2.718281828459045531; % Re-declare with 18 digits past the decimal >> vpa(num, 21) ans = 2.71828182845904553488 % It's the original 20-digit number!!! 回答: 他们是双打。 vpa()只是选择显示超出浮点相对精度的非有效数字,其中printf()和disp()它们截断或归零。 您只得到原始的四位数,因为您选择用来初始化num的文字恰好是二进制double值的精确十进制扩展,因为它是从实际double的扩展输出中复制并粘贴的另一个问题的价值。正如您在“奖金”附录中所示,它不适用于其他附近的值。 更准确地说,Matlab中的所有数字文字都会产生double类型的值。它们将转换为最接近其所代表的十进制值的二进制double值。实际上,超出双精度类型精度限制的文字中的数字会被静默删除。当复制并粘贴vpa的输出以创建新变量时,就像另一个问题的发布者使用e = ...语句所做的那样,您正在从文字中初始化一个值,而不是直接处理上一个的结果表达。 此处的区别仅在于输出格式。我认为这是vpa()正在获取双精度二进制双精度数并将其视为精确值的情况。对于给定的二进制尾数指数值,您可以计算等效于任意多个小数位的十进制数。如果二进制值的精度(“宽度”)有限(与使用任何固定大小的数据类型一样),那么这些十进制数字中只有很多是有效的。 printf()和Matlab的默认显示通过截断输出或将不重要的数字显示为0 vpa()处理此问题vpa()忽略了精度的限制,并继续计算所需的小数位数。 这些额外的数字是伪造的,在某种意义上,如果将它们替换为其他值以产生附近的十进制值,则它们都将被“舍入”为相同的二进制双精度值。 这是一种显示方式。 x的这些值以双精度形式存储时都是相同的,并且将由vpa()表示相同。 x = [ 2.7182818284590455348848081484902650117874145507812500 2.7182818284590455348848081484902650117874145507819999 2.7182818284590455348848 2.71828182845904553488485555555555555555555555555555 exp(1) ] unique(x) 这是另一种演示方式。这是两个非常接近的双打。 x0 = exp(1) x1 = x0 + eps(x0) vpa(x0)和vpa(x1)产生的输出在第16个数字之后会相差很大。但是,您不应创建双vpa(x)值x ,以使vpa(x)产生介于vpa(x0)和vpa(x1)之间的十进制表示形式。 (更新:Amro指出您可以使用fprintf('%bx\n', x)以十六进制格式显示基础二进制值的精确表示形式。您可以使用它来确认文字映射到相同的double。) 我怀疑vpa()行为方式是因为它将输入视为精确值,并且多态支持Symbolic Toolbox中其他Matlab类型,其精度比double更高。这些值将需要通过数字文字之外的其他方式进行初始化,这就是为什么sym()将字符串作为输入并且vpa(exp(1))与vpa(sym('exp(1)')) 。 说得通?抱歉,请耐心等待。 (请注意,我没有Symbolic Toolbox,因此无法自己测试vpa() 。) 更多&回答... |
![]() |
![]() |