Matlab 双精度数字:变量编辑器与 fprintf

Matlab Double Precision Digits: Variable Editor vs. fprintf

this question之后,我在看Matlab中double变量的精度。在那里,建议使用 fprintf 更仔细地查看变量。

奇怪的是Variable Editor和fprintf显示的结果不一样,fprintf多显示一位。

% pi
Variable Editor:       3.141592653589793
fprintf('0.16f\n',pi): 3.1415926535897931
vpa('pi'):             3.1415926535897932384626433832795

% pi / 180
pi180 = pi/180
Variable Editor (pi180)      0.017453292519943
fprintf('%0.16f\n',pi180)    0.0174532925199433
vpa('pi/180')                0.017453292519943295769236907684886

在内部,Matlab 似乎正在处理由 fprintf

打印的精度
>> fprintf('%0.16f\n',0.0174532925199433*10) % value from fprintf
0.1745329251994330
>> fprintf('%0.16f\n',0.017453292519943*10)  % value from Variable Editor
0.1745329251994300
>> fprintf('%0.16f\n',pi180*10)              % internal calculation
0.1745329251994330

为什么会这样?

如果我在函数中使用预先计算的 pi/180,我应该使用来自 fprintf 还是来自变量编辑器的值?

tl;dr 在变量编辑器中,Matlab 在 15 位而不是 16 位处截断。

tl;dr MATLAB 中的变量使用双精度。命令 Window 和变量编辑器中的变量使用相同的精度。唯一的区别是显示格式和打印精度的小数位数。


默认情况下,MATLAB 对其变量使用双精度。 MATLAB 中的这些变量存储在工作区中。命令 Window 和变量编辑器都从同一个工作区中提取它们的变量,因此在下面使用相同的精度。

在变量编辑器和命令 Window 中显示变量的默认格式是 short 格式。您可以使用

检查命令 Window
>> get(0, 'format')
ans =
   short

并通过转至 Preferences -> Variables -> Format 获取变量编辑器。默认情况下,short 格式将变量显示为精确到小数点后 4 位。

在我看来,您已将变量编辑器中变量的默认显示格式更改为 long 格式。此格式显示精度为 15 位小数的双精度变量。 longshort 格式都舍入变量,因此 pi3.14159 被舍入为 3.1416 因为 9 在第 5 位小数short格式显示时的位置

>> format short
>> pi
ans =
    3.1416

这直接等同于fprintf

产生的输出
>> fprintf(1, '%.4f\n', pi);
3.1416

但是,long 格式,我猜,您已将变量编辑器设置为默认格式,四舍五入到小数点后 15 位,因此显示

>> format long
>> pi
ans =
   3.141592653589793

直接等同于

>> fprintf(1, '%.15f\n', pi);
3.141592653589793

当您使用 fprintf(1, '%.16f\n', pi); 时,您将 pi 打印到小数点后 16 位,并且 而不是 15,这是由 long 格式指定的。这就是为什么你的输出是

>> fprintf(1, '%.16f\n', pi);
3.1415926535897931

注意,1 在这末尾。这就是为什么它前面的 3 在您的变量编辑器中显示时没有四舍五入为 4 的原因。

总结

  • MATLAB 中的变量默认使用双精度
  • MATLAB 变量存储在工作区
  • 命令 Window 和变量编辑器中可用的变量均来自工作区并使用相同的精度

预先计算的值

在 MATLAB 中,您应该在函数调用或处理其他数值数据时使用变量名 pi180。这将使用双精度并消除使用 fprintf 或变量编辑器输出的值可能出现的任何复制和粘贴错误。

fprintf 怪癖

tl;dr MATLAB 的 shortlong 格式在 %d%.f、[=49= 之间切换] 和 %.e 说明符取决于最合适的输入方法。


@horchler 指出 %.f 仅直接等同于特定输入的 shortlong 格式,这是正确的。在 fprintf 和 MATLAB 的 shortlong 格式之间,no 直接等效于 all 输入。

例如让我们看看 eps100.5 并尝试打印与 MATLAB 的 shortlong 格式完全相同的数字。

>> format short
>> eps
ans =
   2.2204e-16
>> 100.5
ans =
  100.5000

>> format long
>> eps
ans =
     2.220446049250313e-16
>> 100.5
ans =
     1.005000000000000e+02

现在我们从上面知道 fprintf(1, '%.4f\n', pi);fprintf(1, '%.15f\n', pi); 分别直接等同于 shortlong 对于 pi 但它们是否对于 eps100.5

>> fprintf(1, '%.4f\n', eps);
0.0000
>> fprintf(1, '%.15f\n', eps);
0.000000000000000
>> fprintf(1, '%.4f\n', 100.5);
100.5000
>> fprintf(1, '%.15f\n', 100.5);
100.500000000000000

它们不是唯一的直接等价物是 fprintf(1, '%.4f\n', 100.5);。如果我们尝试使用 %.g 会怎么样?

>> fprintf(1, '%.4g\n', eps);
2.22e-16
>> fprintf(1, '%.15g\n', eps);
2.22044604925031e-16
>> fprintf(1, '%.4g\n', 100.5);
100.5
>> fprintf(1, '%.15g\n', 100.5);
100.5

现在 fprintf 语句中的 none 直接等效。但是,我们可以使用

long 格式生成 eps 的直接等价物
>> fprintf(1, '%.16g\n', eps);
2.220446049250313e-16

因为%g格式说明符.后面的数字指定了有效数字的位数(包括小数点前的数字,.)我们需要使用16 而不是 15.

要为 short 格式的所有这些输入类型生成直接等效项,我们需要混合 %.f%.g%.e 说明符以及调整 field width.

>> format short
>> pi
ans =
    3.1416
>> eps
ans =
   2.2204e-16
>> 100.5
ans =
  100.5000
>> fprintf(1, '%.4f\n', pi);
3.1416
>> fprintf(1, '%.5g\n', eps);
2.2204e-16
>> fprintf(1, '%.4f\n', 100.5);
100.5000

一点都不重要。 long 格式也可以这样做。

>> format long
>> pi
ans =
   3.141592653589793
>> eps
ans =
     2.220446049250313e-16
>> 100.5
ans =
     1.005000000000000e+02
>> fprintf(1, '%.15f\n', pi);
3.141592653589793
>> fprintf(1, '%.16g\n', eps);
2.220446049250313e-16
>> fprintf(1, '%.15e\n', 100.5);
1.005000000000000e+02

甚至比 short 格式更糟糕。

简而言之,MATLAB 的 shortlong 格式在 %d%.f%.g%.e 说明符之间切换,具体取决于关于最合适的输入方法。

补充阅读

您可以通过 format documentation. There is also a helpful document on Display Format for Numeric Values. And lastly, there is information about the Variable Editor and its preferences.

找到有关 MATLAB 中可用的不同显示格式的信息