Main Content

浮点数

“浮点”指一组对实数进行编码的数据类型,包括分数和小数。浮点数据类型允许小数点后有不同位数,而定点数据类型在小数点前后则保留特定位数。因此与定点数据类型相比,浮点数据类型可以表示更广范围的数值。

由于计算机在数字表示和存储方面的内存有限,只能表示有限精度的浮点数有限集合。这种有限精度无法精确表示某些数值,因而会限制需要精确值或高精度的浮点计算的准确度。尽管浮点数有其局限性,但其计算速度快且精度和范围足以求解现实世界的很多问题,因此得到广泛使用。

MATLAB 中的浮点数

MATLAB® 提供遵循 IEEE® 标准 754 的双精度 (double) 和单精度 (single) 浮点数数据类型。默认情况下,MATLAB 以双精度表示浮点数。双精度支持以更高的精度表示数值,但比单精度需要更多内存。为了节省内存,可以使用 single 函数将数值转换为单精度。

如果数值范围约在 –3.4 × 1038 和 3.4 × 1038 之间,您既可以用单精度,也可以用双精度来存储。如果数值超出该范围,请用双精度来存储。

创建双精度数据

由于 MATLAB 的默认数值类型是 double 类型,因此可以用简单的赋值语句创建双精度浮点数。

x = 10;
c = class(x)
c =
   'double'

您可以使用 double 函数将数值数据、字符或字符串以及逻辑数据转换为双精度值。例如,将有符号整数转换为双精度浮点数。

x = int8(-113);
y = double(x)
y =
   -113

创建单精度数据

要创建单精度数值,请使用 single 函数。

x = single(25.783);

还可以使用 single 函数将数值数据、字符或字符串以及逻辑数据转换为单精度。例如,将有符号整数转换为单精度浮点数。

x = int8(-113);
y = single(x)
y =
   single
   -113

MATLAB 如何存储浮点数

默认情况下,MATLAB 根据 IEEE 格式构造其 doublesingle 浮点数据类型,并遵循就近舍入,偶数优先舍入模式。

浮点数 x 的形式如下:

x=1s(1+f)2e

其中:

  • s 确定符号。

  • f 是满足 0 ≤f< 1 的小数(或尾数)。

  • e 是指数。

sfe 分别由内存中有限数量的位确定,其中 fe 取决于数据类型的精度。

存储 double 数需要 64 位,如下表所示。

宽度用法
631存储符号,其中 0 表示正值,1 表示负值
625211存储指数,偏移量为 1023
51052存储尾数

存储 single 数需要 32 位,如下表所示。

宽度用法
311存储符号,其中 0 表示正值,1 表示负值
30238存储指数,偏移量为 127
22023存储尾数

浮点数据类型的最大值和最小值

双精度和单精度数据类型各有其可表示的最大值和最小值。超出可表示范围的数值被视为正无穷或负无穷。但是,由于连续浮点数之间存在间隔并且有些数值可能存在舍入误差,可表示范围内的某些数值无法精确存储。

最大和最小双精度值

分别使用 realmaxrealmin 函数,找出可以用 double 数据类型表示的最大和最小正值。

m = realmax
m =
   1.7977e+308
n = realmin
n =
   2.2251e-308

realmaxrealmin 返回规范化的 IEEE 值。将 realmaxrealmin 乘以 -1 可求出最大和最小负值。大于 realmax 或小于 –realmax 的数值分别被视为正无穷值或负无穷值。

最大和最小单精度值

通过使用参量 "single" 调用 realmaxrealmin 函数,求出可以用 single 数据类型表示的最大和最小正值。

m = realmax("single")
m =
   single
   3.4028e+38
n = realmin("single")
n =
   single
   1.1755e-38

realmax("single")realmin("single") 乘以 –1 可求出最大和最小负值。大于 realmax("single") 或小于 –realmax("single") 的数值分别被视为正无穷值或负无穷值。

最大连续浮点整数

并非所有整数都可以用浮点数据类型表示。最大连续整数 x 是能精确表示的最大整数,所有小于或等于 x 的整数都能精确表示,但 x + 1 无法以浮点格式表示。flintmax 函数返回最大连续整数。例如,使用 flintmax 函数求出双精度浮点格式的最大连续整数,即 253

x = flintmax
x =
   9.0072e+15

求出单精度浮点格式的最大连续整数,即 224

y = flintmax("single")
y =
   single 
   16777216

当您将整数数据类型转换为浮点数据类型时,无法用浮点格式精确表示的整数会损失精度。flintmax 是浮点数,它小于使用相同位数的整数数据类型所能表示的最大整数。例如,双精度的 flintmax 是 253,而 int64 类型的最大值是 264 - 1。因此,将大于 253 的整数转换为双精度会导致精度损失。

浮点数据的精度

浮点数据的精度受下面几个因素的影响:

  • 计算机硬件的限制 - 例如,内存不足的硬件会截断浮点计算的结果。

  • 每个浮点数与下一个更大的浮点数之间的间隔 - 这些间隔存在于任何计算机上,并会限制精度。

浮点数之间的间隔

您可以使用 eps 函数来确定连续浮点数之间的间隔大小。例如,计算 5 和下一个更大的双精度数之间的间距。

e = eps(5)
e =
   8.8818e-16

您无法以双精度格式表示 55 + eps(5) 之间的数值。如果双精度计算返回答案 5,则该结果精确到 eps(5) 范围内。此精度半径通常称为机器精度

各浮点数之间的间隔并不相等。例如,1e10 和下一个更大的双精度数之间的间隔大于 5 和下一个更大的双精度数之间的间隔。

e = eps(1e10)
e =
   1.9073e-06

同样,求 5 和下一个更大的单精度数之间的间距。

x = single(5);
e = eps(x)
e = 
   single 
   4.7684e-07

单精度数之间的间隔大于双精度数之间的间隔,因为单精度数的数量较少。因此,单精度计算的结果不如双精度计算的结果精确。

当您将双精度数转换为单精度数时,可以使用 eps 函数来确定该数值舍入量的上界。例如,当您将双精度数 3.14 转换为单精度数时,该数值的最大舍入量为 eps(single(3.14))

连续浮点整数之间的间隔

flintmax 函数以浮点格式返回最大连续整数。高于此值时,连续浮点整数的间隔大于 1

使用 eps 求出 flintmax 和下一个浮点数之间的间隔:

format long
x = flintmax
x =
   9.007199254740992e+15
e = eps(x)
e =
   2

由于 eps(x)2,因此可以精确表示的下一个更大的浮点数为 x + 2

y = x + e
y =
   9.007199254740994e+15

如果将 1x 相加,结果将舍入到 x

z = x + 1
z =
   9.007199254740992e+15

浮点数的算术运算

您可以在浮点数的算术运算中使用一系列数据类型,结果的数据类型取决于输入类型。但是,当您使用不同数据类型执行运算时,由于逼近或中间转换,某些计算可能不精确。

双精度操作数

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

  • single - 结果为 single 类型。

  • double

  • int8int16int32int64 - 结果的数据类型与整数操作数的数据类型相同。

  • uint8uint16uint32uint64 - 结果的数据类型与整数操作数的数据类型相同。

  • char

  • logical

单精度操作数

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

  • single

  • double

  • char

  • logical

浮点算术的意外结果

MATLAB 中几乎所有运算都是在符合 IEEE 标准 754 的双精度算术中执行的。由于计算机以有限精度表示数值,因此一些计算会产生在数学上不直观的结果。使用浮点数进行计算时可能出现的一些常见问题是舍入误差、抵消、淹没和中间转换。意外的结果并非 MATLAB 中的 Bug,任何使用浮点数的软件都会出现这种情况。如果需要数值的精确有理表示形式,请考虑使用 Symbolic Math Toolbox™。

舍入误差

浮点数的有限精度表示可能导致舍入误差。例如,数值 4/3 不能精确表示为二进制分数。因此,下面的计算会返回数量 eps(1),而不是 0

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

同样,由于 pi 不是 π 的精确表示,sin(pi) 也不精确为零。

x = sin(pi)
x =
   1.2246e-16

当对浮点数执行许多运算时,误差会不断累积和复合,舍入误差最为显著。最佳做法是尽可能减少运算次数。

抵消

根据 eps 的测量,当您从数量级大致相同的一个数中减去另一个数时,可能发生抵消。例如,eps(2^53)2,因此数值 2^53 + 12^53 具有相同的浮点表示。

x = (2^53 + 1) - 2^53
x =
   0

请尽可能尝试用一种等效形式重写计算,以避免发生抵消。

淹没

当您对数量级相差特别大的浮点数执行运算时,可能发生淹没。例如,下面的计算显示精度损失会使加法运算失去意义。

x = 1 + 1e-16
x =  
   1

中间转换

当您使用不同数据类型执行算术时,中间计算和转换可能会产生意外的结果。例如,虽然 xy 均为 0.2,但将它们相减会产生非零结果。原因是在执行减法之前 y 先转换为 double 类型。然后此减法的结果再转换为 single 类型的 z

format long 
x = 0.2
x = 
   0.200000000000000
y = single(0.2)
y = 
   single
   0.2000000
z = x - y
z = 
   single 
   -2.9802323e-09

线性代数

浮点算术中的常见问题(如上述问题)在应用于线性代数问题时会复合,因为相关计算通常由多个步骤组成。例如,在求解线性方程组 Ax = b 时,MATLAB 警告结果可能不准确,因为操作数矩阵 A 为病态矩阵。

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

参考

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

另请参阅

函数