在 MATLAB 中,默认情况下变量真的是双精度的吗? [英] In MATLAB, are variables REALLY double-precision by default?

查看:28
本文介绍了在 MATLAB 中,默认情况下变量真的是双精度的吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个问题源于我在进一步调查这个问题后注意到的一些奇怪的事情......em>

This question arose out of something strange that I noticed after investigating this question further...

我一直认为 MATLAB 变量默认为双精度.所以,如果我要做一些事情,比如声明一个小数点后有 20 位数字的变量:

I always understood MATLAB variables to be double-precision by default. So, if I were to do something like declare a variable with 20 digits after the decimal point:

>> num = 2.71828182845904553488;
>> class(num)  % Display the variable type
ans =
double

我希望最后 4 位数字被忽略,因为 浮点数相对准确度约为 10-16:

I would expect the last 4 digits to be ignored, since the floating-point relative accuracy is on the order of 10-16:

>> eps(num)
ans =
    4.440892098500626e-016

如果我尝试显示小数点后超过 16 位的数字(使用 fprintfsprintf),我得到了我期望看到的:

If I try to display the number with more than 16 digits after the decimal point (using either fprintf or sprintf), I get what I expect to see:

>> fprintf('%0.20f
', num)
2.71828182845904550000
>> sprintf('%0.20f', num)
ans =
2.71828182845904550000

换句话说,数字 17 到 20 都是 0.

In other words, digits 17 through 20 are all 0.

但是当我将 num 传递给 变量时,事情变得很奇怪Symbolic Toolbox 中的精度算术函数,告诉它代表使用 21 位精度的数字:

But things get weird when I pass num to the variable precision arithmetic function in the Symbolic Toolbox, telling it to represent the number using 21 digits of precision:

>> vpa(num, 21)
ans =
2.71828182845904553488

什么?!最后四位数字又出现了!当我输入的原始数字存储为双精度变量 num 时,它们不应该丢失吗?由于num在传递给vpa时是一个双精度变量,那么vpa是怎么知道它们是什么的?

WHAT?! Those last 4 digits have reappeared! Shouldn't they have been lost when the original number I entered was stored as a double-precision variable num? Since num is a double-precision variable when it is passed to vpa, how did vpa know what they were?

我对正在发生的事情的最佳猜测是 MATLAB 在内部表示 num 比双精度更高,因为我将它初始化为一个数字,小数点后的位数比双精度变量多可以处理.这真的是正在发生的事情,还是正在发生其他事情?

My best guess as to what is happening is that MATLAB internally represents num with more precision than a double since I initialized it to a number with more digits past the decimal point than a double-precision variable could handle. Is this really what is happening, or is something else going on?


额外奖励:如果您还没有因上述原因患上偏头痛,这里还有一个额外的困惑来源...

BONUS: And here's an additional source of confusion if you don't already have a migraine from the above...

>> 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() 截断或将它们归零.

They're doubles. vpa() is simply choosing to display non-significant digits beyond the floating point relative accuracy, where printf() and disp() truncate or zero them out.

你只得到你原来的四位数,因为你选择初始化 num 的文字恰好是二进制双精度值的精确十进制扩展,因为它被复制和粘贴从另一个问题的实际 double 值的扩展的输出.正如您在奖励"附录中所示,它不适用于其他附近的值.

You're only getting your original four digits back out because the literal you chose to initialize num with just happens to be the exact decimal expansion of a binary double value, because it was copy and pasted from the output of the expansion of an actual double value from the other question. It won't work for other nearby values, as you show in your "BONUS" addendum.

更准确地说,Matlab 中的所有数字文字都会产生 double 类型的值.它们被转换为最接近它们所代表的十进制值的二进制双精度值.实际上,超出 double 类型精度限制的文字中的数字会被悄悄删除.当您复制并粘贴 vpa 的输出以创建一个新变量时,就像另一个问题的发布者对 e = ... 语句所做的那样,您正在初始化一个值来自文字,而不是直接处理前一个表达式的结果.

More precisely, all numeric literals in Matlab produce values of type double. They get converted to the binary double value that is nearest to the decimal value they represent. In effect, digits in a literal beyond the limit of precision of the double type are silently dropped. When you copy and paste the output of vpa to create a new variable, as the other question's poster did with the e = ... statement, you're initializing a value from a literal, instead of dealing directly with the result of a previous expression.

这里的区别仅在于输出格式.我认为正在发生的事情是 vpa() 正在采用双精度二进制 double 并将其视为精确值.对于给定的二进制尾数指数值,您可以计算相当于任意多位小数的十进制数.如果二进制值的精度(宽度")有限,就像使用任何固定大小的数据类型一样,那么这些十进制数字中只有这么多是有效的.printf() 和 Matlab 的默认显示通过截断输出或将非有效数字显示为 0 来处理此问题. vpa() 忽略精度限制并继续计算为根据您的要求保留多个小数位.

The differences here are just in output formatting. I think what's going on is that vpa() is taking that double precision binary double and treating it as an exact value. For a given binary mantissa-exponent value, you can calculate the decimal equivalent to arbitrarily many decimal places. If you have a limited precision ("width") in the binary value, as you do with any fixed-size data type, only so many of those decimal digits are significant. printf() and Matlab's default display handle this by truncating the output or displaying non-significant digits as 0. vpa() is ignoring the limits of precision and continuing to calculate as many decimal places as you request.

那些额外的数字是假的,从某种意义上说,如果它们被其他值替换以产生附近的十进制值,它们都会被四舍五入"为相同的二进制双精度值.

Those additional digits are bogus, in the sense that if they were replaced by other values to produce a nearby decimal value, they would all get "rounded" to the same binary double value.

这是一种展示方式.x 的这些值在以双精度形式存储时都是相同的,并且都将通过 vpa() 表示相同.

Here's a way to show it. These values of x are all the same when stored in doubles, and will all be represented the same by vpa().

x = [
    2.7182818284590455348848081484902650117874145507812500
    2.7182818284590455348848081484902650117874145507819999
    2.7182818284590455348848
    2.71828182845904553488485555555555555555555555555555
    exp(1)
    ]
unique(x)

这是证明它的另一种方式.这是两个非常接近的双打.

Here's another way of demonstrating it. Here are two doubles that are very close to each other.

x0 = exp(1)
x1 = x0 + eps(x0)

vpa(x0)vpa(x1) 应该产生超过 16 位的输出.但是,您不应该创建双精度值 x,这样 vpa(x) 会生成介于 vpa(x0)vpa(x1).

vpa(x0) and vpa(x1) should produce outputs that differ a lot past the 16th digit. However, you shouldn't be able to create a double value x such that vpa(x) produces a decimal representation that falls between vpa(x0) and vpa(x1).

(更新:Amro 指出您可以使用 fprintf('%bx ', x) 以十六进制格式显示底层二进制值的精确表示.您可以使用它来确认文字映射到同一个双精度.)

(UPDATE: Amro points out that you can use fprintf('%bx ', x) to display an exact representation of the underlying binary value in hex format. You can use this to confirm the literals map to the same double.)

我怀疑 vpa() 这样做是因为它将其输入视为精确值,并且多态地支持符号工具箱中精度高于双精度的其他 Matlab 类型.这些值将需要通过数字文字以外的方式进行初始化,这就是为什么 sym() 将字符串作为输入并且 vpa(exp(1)) 不同于vpa(sym('exp(1)')).

I suspect vpa() behaves this way because it treats its inputs as exact values, and polymorphically supports other Matlab types from the Symbolic Toolbox that have more precision than doubles. Those values will need to be initialized by means other than numeric literals, which is why sym() takes a string as an input and vpa(exp(1)) differs from vpa(sym('exp(1)')).

有意义吗?抱歉啰嗦.

(注意我没有符号工具箱,所以我不能自己测试 vpa().)

(Note I don't have the Symbolic Toolbox so I can't test vpa() myself.)

这篇关于在 MATLAB 中,默认情况下变量真的是双精度的吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆