本页对应的英文页面已更新,但尚未翻译。 若要查看最新内容,请点击此处访问英文页面。

浮点数

MATLAB® 以双精度或单精度格式表示浮点数。默认为双精度,但您可以通过一个简单的转换函数将任何数值转换为单精度数值。

双精度浮点

MATLAB 根据适用于双精度的 IEEE® 754 标准来构造双精度(即 double)数据类型。以 double 形式存储的任何值都需要 64 位,并按照下表所示进行格式化:

用法

63

符号(0 = 正号、1 = 负号)

6252

指数,偏差为 1023

510

数值 1.f 的小数 f

单精度浮点

MATLAB 根据适用于单精度的 IEEE 754 标准来构造单精度(即 single)数据类型。以 single 形式存储的任何值都需要 32 位,并按照下表所示进行格式化:

用法

31

符号(0 = 正号、1 = 负号)

3023

指数,偏差为 127

220

数值 1.f 的小数 f

由于 MATLAB 使用 32 位来存储 single 类型的数值,因此与使用 64 位的 double 类型的数值相比,前者需要的内存更少。但是,由于它们是使用较少的位存储的,因此 single 类型的数值所呈现的精度要低于 double 类型的数值。

创建浮点数据

一般使用双精度来存储大于 3.4 x 1038 或约小于 -3.4 x 1038 的值。对于位于这两个范围之间的数值,您可以使用双精度,也可以使用单精度,但单精度需要的内存更少。

创建双精度数据

由于 MATLAB 的默认数值类型为 double,因此您可以通过一个简单的赋值语句来创建 double 值:

x = 25.783;

whos 函数显示,MATLAB 已为您刚在 x 中存储的值创建了一个 double 类型的 1x1 数组:

whos x
  Name      Size                   Bytes  Class

  x         1x1                        8  double

如果您只想验证 x 是否为浮点数,请使用 isfloat。如果输入为浮点数,此函数将返回逻辑值 1 (true),否则返回逻辑值 0 (false):

isfloat(x)
ans =

  logical

   1

可以使用 MATLAB 函数 double 将其他数值数据、字符或字符串以及逻辑数据转换为双精度值。以下示例将有符号整数转换为双精度浮点数:

y = int64(-589324077574);          % Create a 64-bit integer

x = double(y)                      % Convert to double
x =
  -5.8932e+11

创建单精度数据

由于 MATLAB 默认情况下以 double 形式存储数值数据,因此您需要使用 single 转换函数来创建单精度数:

x = single(25.783);

whos 函数在结构体中返回变量 x 的属性。此结构体的 bytes 字段显示,当以 single 形式存储 x 时,该变量仅需要 4 字节,而以 double 形式存储则需要 8 字节:

xAttrib = whos('x');
xAttrib.bytes
ans =
     4

可以使用 single 函数将其他数值数据、字符或字符串以及逻辑数据转换为单精度值。以下示例将有符号整数转换为单精度浮点数:

y = int64(-589324077574);          % Create a 64-bit integer

x = single(y)                      % Convert to single
x =

  single

 -5.8932e+11

浮点数的算术运算

此部分介绍您可以在算术运算中将哪些类与浮点数一起使用。

双精度运算

您可以使用 double 和以下的任何其他类来执行基本算术运算。如果一个或多个操作数为整数(标量或数组),则 double 操作数必须为标量。运算结果默认为 double 类型,除非另有说明:

  • single - 结果为 single 类型

  • double

  • int*uint* - 结果与整数操作数具有相同的数据类型

  • char

  • logical

以下示例对 chardouble 类型的数据执行算术运算。结果为 double 类型:

c = 'uppercase' - 32;

class(c)
ans =
   double

char(c)
ans =
   UPPERCASE

单精度运算

您可以使用 single 和以下的任何其他类来执行基本算术运算。运算结果始终为 single

  • single

  • double

  • char

  • logical

在以下示例中,7.5 默认为 double 类型,结果为 single 类型:

x = single([1.32 3.47 5.28]) .* 7.5;

class(x)
ans =
   single

浮点类的最大值和最小值

doublesingle 类都存在可以用该类型表示的最大数和最小数。

最大和最小双精度值

MATLAB 函数 realmaxrealmin 分别返回可以用 double 数据类型表示的最大值和最小值:

str = 'The range for double is:\n\t%g to %g and\n\t %g to  %g';
sprintf(str, -realmax, -realmin, realmin, realmax)

ans =
The range for double is:
   -1.79769e+308 to -2.22507e-308 and
    2.22507e-308 to  1.79769e+308

大于 realmax 或小于 -realmax 的数分别被赋予正无穷大和负无穷大的值:

realmax + .0001e+308
ans =
   Inf

-realmax - .0001e+308
ans =
  -Inf

最大和最小单精度值

在用参数 'single' 调用 MATLAB 函数 realmaxrealmin 时,这两个函数会分别返回可以用 single 数据类型表示的最大值和最小值:

str = 'The range for single is:\n\t%g to %g and\n\t %g to  %g';
sprintf(str, -realmax('single'), -realmin('single'), ...
    realmin('single'), realmax('single'))

ans =
The range for single is:
	-3.40282e+38 to -1.17549e-38 and
	 1.17549e-38 to  3.40282e+38

大于 realmax('single') 或小于 -realmax('single') 的数分别被赋予正无穷大和负无穷大的值:

realmax('single') + .0001e+038
ans =

  single

   Inf

-realmax('single') - .0001e+038
ans =

  single

  -Inf

浮点数据的精度

如果浮点算术计算的结果不如预期的精确,可能是由于您的计算机硬件的限制所致。由于硬件缺乏足够的位而无法呈现具有完美精度的结果,计算机可能会将结果值截断,使得结果值不够准确。

双精度数的精度

由于双精度数的数量有限,因此您无法在双精度存储中表示所有数值。在任何计算机上,每个双精度数和下一个更大的双精度数之间都存在一个较小的间隔。您可以使用 eps 函数确定此间隔的大小,该大小限制了您的结果的精度。例如,要计算 5 和下一个更大的双精度数之间的间距,请输入

format long

eps(5)
ans =
     8.881784197001252e-16

这表明,5 和 5 + eps(5) 之间不存在任何双精度数。如果某个双精度计算返回答案 5,则结果仅精确到 eps(5) 之内。

eps(x) 的值取决于 x。以下示例显示,当 x 变得更大时,eps(x) 也会变得更大:

eps(50)
ans =
     7.105427357601002e-15

如果您输入不带输入参数的 eps,MATLAB 将返回 eps(1) 的值(从 1 到下一个更大的双精度数之间的间距)。

单精度数的精度

同样,两个单精度数之间也存在间隔。如果 x 的类型为 single,则 eps(x) 返回 x 和下一个更大的单精度数之间的间距。例如,

x = single(5);
eps(x)

返回

ans =

  single

  4.7684e-07

请注意,此结果大于 eps(5)。由于单精度数的数量少于双精度数的数量,因此单精度数之间的间隔也大于双精度数之间的间隔。这意味着,单精度算术运算的结果精度要低于双精度算术运算的结果精度。

对于类型为 double 的双精度数 xeps(single(x)) 的计算值即为将 xdouble 转换为 single 时的舍入上限。例如,当您将双精度数 3.14 转换为 single 时,它会通过以下方式进行舍入

double(single(3.14) - 3.14)
ans =
   1.0490e-07

3.14 舍入的数量小于

eps(single(3.14))
ans =

  single

  2.3842e-07

避免浮点算术运算出现常见问题

MATLAB 中几乎所有运算都是通过符合 IEEE 754 标准的双精度算术运算执行的。由于计算机仅将数值表示为有限精度(双精度需要 52 个尾数位),因此计算有时会生成数学上的非预期结果。务必注意,这些结果并非 MATLAB 中的错误。

使用以下示例来帮助您确定这些情况:

示例 1 - 舍入或您所获得的不是所期望的

十进制数 4/3 不能精确表示为二进制分数。为此,以下计算的结果不是零,而是显示数量 eps

e = 1 - 3*(4/3 - 1)

e =
   2.2204e-16

同样,0.1 也不能精确表示为二进制数。因此,您会发现以下非预期行为:

a = 0.0;
for i = 1:10
  a = a + 0.1;
end
a == 1
ans =

  logical

   0

请注意,计算中运算的顺序会很重要:

b = 1e-16 + 1 - 1e-16;
c = 1e-16 - 1e-16 + 1;
b == c
ans =

  logical

   0

浮点数之间存在间隔。当数值变得越大时,间隔也会变得越大,如以下所示:

(2^53 + 1) - 2^53

ans =
     0

由于 pi 实际上不是 π,因此 sin(pi) 不精确为零并不足为奇:

sin(pi)

ans =
     1.224646799147353e-16

示例 2 - 具有灾难性后果的取消操作

对几乎相等的操作数执行减法时,有时可能会发生意外取消。以下是因淹没(使加法没有意义的精度损失)导致的取消的示例。

sqrt(1e-16 + 1) - 1

ans =
     0

MATLAB 中的某些函数(例如 expm1log1p)可用于弥补这种灾难性取消所造成的影响。

示例 3 - 浮点运算和线性代数

解决线性代数的问题时,舍入、取消和浮点算术运算的其他一些特性结合起来时,可能产生令人意想不到的运算。MATLAB 会警告下面的矩阵 A 是病态的,因此即便是细微的扰动,都可能对方程组 Ax = b 产生很大的影响:

A = diag([2 eps]); 
b = [2; eps]; 
y = A\b; 
Warning: Matrix is close to singular or badly scaled.
         Results may be inaccurate. RCOND = 1.110223e-16.

这些只是几个例子,用于说明 IEEE 浮点算术运算如何影响 MATLAB 中的计算。请注意,IEEE 754 算术运算中执行的所有计算都会受到影响,这包括用 C 或 FORTRAN 编写的应用程序以及 MATLAB。

参考

[1] Moler, Cleve. “Floating Points.” MATLAB News and Notes. Fall, 1996.

[2] Moler, Cleve. Numerical Computing with MATLAB. Natick, MA: The MathWorks, Inc., 2004.