浮点数
“浮点”指一组对实数进行编码的数据类型,包括分数和小数。浮点数据类型允许小数点后有不同位数,而定点数据类型在小数点前后则保留特定位数。因此与定点数据类型相比,浮点数据类型可以表示更广范围的数值。
由于计算机在数字表示和存储方面的内存有限,只能表示有限精度的浮点数有限集合。这种有限精度无法精确表示某些数值,因而会限制需要精确值或高精度的浮点计算的准确度。尽管浮点数有其限制,但其计算速度快且精度和范围足以求解现实世界的很多问题,因此得到广泛使用。
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 格式构造其 double 和 single 浮点数据类型,并遵循就近舍入,偶数优先舍入模式。
浮点数 x 的形式如下:
其中:
s 确定符号。
f 是满足 0 ≤f< 1 的小数(或尾数)。
e 是指数。
s、f 和 e 分别由内存中有限数量的位确定,其中 f 和 e 取决于数据类型的精度。
存储 double 数需要 64 位,如下表所示。
| 位 | 宽度 | 用法 |
|---|---|---|
63 | 1 | 存储符号,其中 0 表示正值,1 表示负值 |
62 到 52 | 11 | 存储指数,偏移量为 1023 |
51 到 0 | 52 | 存储尾数 |
存储 single 数需要 32 位,如下表所示。
| 位 | 宽度 | 用法 |
|---|---|---|
31 | 1 | 存储符号,其中 0 表示正值,1 表示负值 |
30 到 23 | 8 | 存储指数,偏移量为 127 |
22 到 0 | 23 | 存储尾数 |
浮点数据类型的最大值和最小值
双精度和单精度数据类型各有其可表示的最大值和最小值。超出可表示范围的数值被视为正无穷或负无穷。但是,由于连续浮点数之间存在间隔并且有些数值可能存在舍入误差,可表示范围内的某些数值无法精确存储。
最大和最小双精度值
分别使用 realmax 和 realmin 函数,找出可以用 double 数据类型表示的最大和最小正值。
m = realmax
m = 1.7977e+308
n = realmin
n = 2.2251e-308
realmax 和 realmin 返回规范化的 IEEE 值。将 realmax 和 realmin 乘以 -1 可求出最大和最小负值。大于 realmax 或小于 –realmax 的数值分别被视为正无穷值或负无穷值。
最大和最小单精度值
通过使用参量 "single" 调用 realmax 和 realmin 函数,求出可以用 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
您无法以双精度格式表示 5 和 5 + 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 = flintmaxx = 9.007199254740992e+15
e = eps(x)
e = 2
由于 eps(x) 为 2,因此可以精确表示的下一个更大的浮点数为 x + 2。
y = x + e
y = 9.007199254740994e+15
如果将 1 与 x 相加,结果将舍入到 x。
z = x + 1
z = 9.007199254740992e+15
浮点数的算术运算
您可以在浮点数的算术运算中使用一系列数据类型,结果的数据类型取决于输入类型。但是,当您使用不同数据类型执行运算时,由于逼近或中间转换,某些计算可能不精确。
双精度操作数
您可以使用 double 和以下的任何其他数据类型来执行基本算术运算。如果一个或多个操作数为整数标量或数组,则 double 操作数必须为标量。运算结果默认为 double 类型,除非另有说明。
single- 结果为single类型。doubleint8、int16、int32、int64- 结果的数据类型与整数操作数的数据类型相同。uint8、uint16、uint32、uint64- 结果的数据类型与整数操作数的数据类型相同。charlogical
单精度操作数
您可以使用 single 和以下的任何其他数据类型来执行基本算术运算。结果为 single 类型。
singledoublecharlogical
浮点算术的意外结果
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 + 1 和 2^53 具有相同的浮点表示。
x = (2^53 + 1) - 2^53
x = 0
请尽可能尝试用一种等效形式重写计算,以避免发生抵消。
淹没
当您对数量级相差特别大的浮点数执行运算时,可能发生淹没。例如,下面的计算显示精度损失会使加法运算失去意义。
x = 1 + 1e-16
x = 1
中间转换
当您使用不同数据类型执行算术时,中间计算和转换可能会产生意外的结果。例如,虽然 x 和 y 均为 0.2,但将它们相减会产生非零结果。原因是在执行减法之前 y 先转换为 double 类型。然后此减法的结果再转换为 single 类型的 z。
format long
x = 0.2x = 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.