在MATLAB中,variables真的是双精度默认?

这个问题是由于我在进一步调查这个问题之后发现的一些奇怪的东西而产生的。

我总是把MATLABvariables理解为默认的双精度 。 所以,如果我要做一些小数点后面20位数的variables声明:

>> 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。

但是当我把符号工具箱中的variables精度算术函数传递给num时,事情变得很奇怪,告诉它用21位数的精度来表示数字:

 >> vpa(num,21) ans = 2.71828182845904553488 

什么?! 最后4位数字再次出现! 当我input的原始数字被存储为双精度variablesnum时,不应该丢失它们吗? 既然num是一个双精度variables,当它传递给vpavpa是如何知道它们是什么?

我最好的猜测是,MATLAB在内部用比double更高的精度代表num ,因为我把它初始化为一个数字,比double-precisionvariables可以处理的小数点还多。 这究竟是发生了什么,还是其他的事情呢?


奖金:如果你还没有从上面的偏头痛,这是另一个混​​乱的来源…

 >> 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()只是简单地select显示浮点相对精度以外的非有效数字,其中printf()和disp()将其截断或归零。

你只能得到原来的四位数字,因为你select初始化num的字面值恰好是二进制double值的确切的十进制扩展,因为它是从实际的double的扩展的输出复制和粘贴的来自另一个问题的价值。 它不适用于其他附近的值,如您在“奖金”附录中所示。

更确切地说,Matlab中的所有数字文字都会生成doubletypes的值。 它们被转换成最接近它们所表示的十进制值的二进制double值。 实际上,超出doubletypes的精度限制的数字将被静默地丢弃。 当你复制并粘贴vpa的输出来创build一个新的variables时,就像另一个问题的海报用“e = …”语句做的那样,你正在从一个文字初始化一个值,而不是直接处理以前的expression。

这里的差异只是输出格式。 我认为发生了什么是vpa()正在采取双精度二进制双精度和对待它作为一个确切的价值。 对于给定的二进制尾数指数值,可以计算相当于任意多位小数的十进制数。 如果二进制值中的精度(“宽度”)有限,则与使用任何固定大小的数据types时一样,只有那么多的十进制数才是重要的。 Sprintf()和Matlab的默认显示通过截断输出或将无效数字显示为0来处理这个问题.Vpa()忽略了精度的限制,并继续按照您的要求计算出许多小数位数。

那些额外的数字是假的,从这个意义上说,如果它们被其他值replace产生一个附近的十进制值,他们都将被“四舍五入”到相同的二进制double值。

这是一个显示它的方法。 这些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位相差很多。 但是,您不应该创build一个double值x,使vpa(x)产生一个介于vpa(x0)和vpa(x1)之间的十进制表示forms。

(更新:Amro指出,你可以使用fprintf('%bx\n', x)以hex格式显示底层二进制值的确切表示,你可以用这个来确认文本映射到同一个double。

我怀疑vpa()的行为是这样的,因为它把它的input视为精确的值,并且多态地支持符号工具箱中比双精度更精确的其他Matlabtypes。 这些值将需要通过数字文字以外的方式进行初始化,这就是为什么sym()将string作为input并且“vpa(exp(1))”与“vpa(sym('exp(1)')不同的原因)”。

合理? 抱歉,啰嗦。

(注意我没有符号工具箱,所以我不能testingvpa()我自己。)