🔥 高优先级
IEEE 浮点数表示的方法非常重要,每年选择题都必考,需要能够熟练计算 IEEE 浮点数的二进制和十进制之间的关联。
实数的二进制表示
实数在计算机中的存储遵循 IEEE 浮点数标准,但在这里为了方便理解 IEEE 标准,这里首先阐明一般 实数 在计算机中是如何存储的。
在这里 实数 分为两个部分存储:整数部分 和 小数部分 ,两个部分在逻辑上用 · 隔开。
比如对于以下 浮点数 的二进制表示:
dmdm−1⋯d1d0⋅d−1d−2⋯d−n
其中每一位对应的数值如下表所示:
| dm | dm−1 | ⋯ | d1 | d0 | d−1 | d−2 | ⋯ | d−n |
|---|---|---|---|---|---|---|---|---|
| 2m | 2m−1 | ⋯ | 2 | 1 | 1/2 | 1/4 | ⋯ | 1/2n |
上述二进制表示对应的数值为
b=i=−n∑m2i×bi
其中 bi=0 或 bi=1 ,表示第 i 为是 0 还是 1。
举例说明如何使用上述表示法计算 实数 :
- 101.112 对应的数值为 1×22+0×21+1×20+1×2−1+1×2−2=5.75
- 1011.12 对应的数值为 8+0+2+1+21=11.5
字面值转二进制
举个实际的例子,将 1.2 转换为二进制表示。
整数部分 1 的二进制是 1。
小数部分 0.2 的二进制表示是一个无限循环小数。通过不断乘以 2,可以得到近似的二进制:
- 0.2 × 2 = 0.4 → 整数部分 0
- 0.4 × 2 = 0.8 → 整数部分 0
- 0.8 × 2 = 1.6 → 整数部分 1
- 0.6 × 2 = 1.2 → 整数部分 1
- 0.2 × 2 = 0.4 → 重复…
于是, 1.2 在二进制中近似为 1.0011001100110011...。
IEEE 浮点数表示
上述 浮点数 存储方式的缺点在于如果要表示比较大的数,就需要比较多的二进制位数,比如对于 5×2100 就需要 103 位。IEEE 表示 就解决了这个问题,在 IEEE 表示 中,浮点数 V 被表示为 V=(−1)s×M×2E ,其中 s,M,E 的含义如下:
- s 为 符号位
- M 为 乘法因子
- E 为 指数部分
IEEE 754 标准 是定义浮点数表示和算术的国际标准,它定义了多种不同精度的浮点数格式,但最常见的是 单精度 single precesion (32 位)和 双精度 double precesion (64 位),浮点数分为 s(符号位 )、exp(阶码 )、frac(尾数 )三个部分存储:
1 位的 s 与上述计算公式中的 符号位 s 相同,位于浮点数二进制表示的 最高位 ,标志了浮点数的正负,如果 s=1 的话 V 是负数,如果 s=0 的话 V 为正数
k 位的 exp=ek−1⋯e1e0 用于计算 指数部分 E ( exp 为 unsigned 值,但不能为全 0 或全 1),其中 E=exp−Bias , Bias=2k−1−1
对于 单精度 浮点数
- k=8 , Bias=28−1−1=127
- 1≤exp≤254
- −126≤E≤127
对于 双精度 浮点数
k=11 , Bias=211−1−1=1023
1≤exp≤2046
−1022≤E≤1023
n 位的 frac=0⋅fn−1⋯f1f0 用于计算 因子 M ,其中 M=1+frac , frac 表示的小数计算方式见 实数的二进制表示
对于 单精度 浮点数, n=23 , M 的最大值为 2−2−23 , M 最小值为 1
对于 双精度 浮点数, n=52 , M 的最大值为 2−2−52 , M 最小值为 1
总结 单精度 和 双精度 浮点数 表示如下:
| 类型 | 符号位 s | 阶码 exp | 尾数 frac | 总位数 | 偏置值 |
|---|---|---|---|---|---|
| 单精度 | 1 | 8 | 23 | 32 | 127 |
| 双精度 | 1 | 11 | 52 | 64 | 1023 |
单精度 浮点数表示为:
(−1)s×1.frac×2exp−127
双精度 浮点数表示为:
(−1)s×1.frac×2exp−1023
总结 单精度 和 双精度 浮点数中各个字段的范围如下图所示:
异常值
注意 IEEE 浮点数 表示分为 Normalized Values (正常值)和 Denormalized Values (非正常值)以及特殊值 ,上节中提到的 IEEE 浮点数 计算方法只适用于 正常值 ,
正常值 的 阶码 (exp)不能为全 0 或全 1。
下图是 浮点数 各种类型的图示(以 单精度 为例):

- 非正常值 (Denormalized)的 阶码 全为 0
- 无穷大 (Infinity)的 阶码 全为 1,尾数 位为 0
- 非数字 (NaN,Not a Number)的 阶码 全为 1,尾数 位不为 0
需要注意的是 非正常值 的 浮点数 计算公式 与 正常值 不同:
value=(−1)sign×0.f×21−bias
注意这里的:
- 没有隐含的 “1”,因为它是 非正规数 。
- 指数固定为 1−bias (而不是 e−bias ,因为 阶码 是全 0)
- 这是为了在非常接近 0 的地方保持精度连续性 (即从最小正规数向 0 过渡的“填充区”)
下表总结了给出了 浮点数 表示各种情况的有效值计算:
| 类型 | 阶码(exp) | 尾数(fraction) | 有效值公式 |
|---|---|---|---|
| 正常值 | 非全 0、非全 1 | f | ±1.f×2e−bias |
| 非正常值 | 全 0 | f (必须非 0,否则是 0 ) | ± 0.f×21−bias |
| ±0 | 全 0 | 全 0 | ±0 |
| ±∞ | 全 1 | 全 0 | ±∞ |
| NaN | 全 1 | 非 0 | Not a Number(结果非法或未定义) |
字面值转二进制
前文已经提到如果我们有 浮点数 的 IEEE 二进制表示 ,如何将其转化为实际的 浮点数 ,就是通过如下的公式:
(−1)s×1.frac×2exp−bias
还有一种常见的考题是给定我们一个 浮点数字面值 ,比如 2.25 ,然后让我们去反推它的二进制表示,这里有没有什么简便的解法呢?
最简便的方法还是反向转换 ,即将一个 浮点数 表示为 一点几几 ( 1.frac )乘以二的多少次方( 2n )的格式,有这两部分可以分别计算出 阶码 和尾数 ,然后符号位 由数字的正负判断。
以 2.25 为例,如果我们想得到该 浮点数 的 单精度 表示:
2.25=1.125×21=89×21=(1+81)×21=(1+2−3)×21
由此可以计算出 浮点数 的各个部分:
- 符号位 为 0
- 阶码 为 1+127=128 ,二进制表示为
1000 0000B - 尾数 为
0010 0000 0000 ....
所以 浮点数 的二进制为 0100 0000 0001 0000 ...,十六进制为 40100000H 。
一般而言,试题只会考察这种没有精度损失的 浮点数二进制转换 ,对于有精度损失的情况,由于比较繁琐,基本不会考察,其 尾数 部分的计算与 一般实数字面值转二进制 相同。
表示精度
上述的例子是一个比较理想的例子, 2.25 可以精确地用 浮点数 表示。但在真实场景中,很多 实数 都是无法精确地用 浮点数 表示的。比如 1.2 这个数:
1.2=(1+51)×21
其中 51 无法表示为若干个 2n1 之和,所以对于这种情况,我们只能尽量地去接近这个数。
若要理解如何接近这个数,我们首先要理解 精度 的概念。这里我们首先从简单的例子出发,假设 阶码 只有 3 位,那么这些 尾数 可以被精确表示:
i=0∑3f×2i,f∈{0,1}
在数轴中对应 [0, 1] 区间中的 8 个点:
如果一个尾数的大小与这些点都不相同的话,则需要找一个临近的点来近似,这也是导致 精度 丢失的原因:尾数的二进制表示法无法精确地表示 [0, 1] 中的每一个 实数 ,对于无法精确表示的,只能去近似。
但是这种误差可以随着 尾数 位数的增加而不断减小,比如对于 单精度浮点数 表示,尾数 (frac)为 23 位,可以精确表示以下这些小数:
0,2231,2232,2233,⋯,223223−1,1
双精度浮点数 表示,尾数 为 52 位,可以精确表示以下这些小数:
0,2521,2522,2523,⋯,252252−1,1
所以 尾数位数越多 ,精度越高 ,用以近似表示某些 实数 时,误差更小。
注意
舍入 是在数值计算中将一个数字转换为特定精度的过程。由于计算机中的 浮点数 表示有限,许多数学运算结果不能完全精确地用 浮点数 表示,因此需要 舍入 来逼近这些结果。
浮点数加减
💡 低优先级
浮点数加减操作考察得不是很多,但是如果深入掌握了 IEEE 浮点数表示的原理的话,这个掌握其过程也不是很难。
浮点数 加减计算过程包含以下几个步骤:对阶 、尾数加减 、尾数规格化 。
- 对阶 :为了进行加减运算,两个 浮点数 必须具有相同的指数,这里采用低阶向高阶对齐的原则,过程如下:
- 比较两个浮点数的 指数 。
- 将较小指数的浮点数的 尾数右移 ,直到两个指数相等。
- 右移过程中,需要注意尾数的 精度损失 (尾数右移时可能会丢失低位精度)。
- 尾数加减 :在指数对齐后,直接对两个 浮点数 的 尾数 进行加减。
- 由于尾数已经对齐,可以直接进行 加减操作 。
- 根据操作结果可能需要处理进位或借位。
- 尾数规格化 :确保结果符合标准化浮点数的格式,即尾数以 1 开头。
- 如果结果尾数不符合 1.xxxx 格式,则需要进行 规格化调整 。
- 左移尾数并相应减少指数,或右移尾数并相应增加指数。
- 规格化后,可能还需要进行 舍入 ,以符合尾数的位数限制。
- 根据舍入模式(如“向偶数舍入”、“向零舍入”等)完成必要操作。
在 对阶 和 尾数规格化 的过程中,由于可能存在 尾数 右移,所以可能会导致 精度缺失 。
因为 IEEE 浮点数尾数的位数是有限的,如果右移的过程中尾数中最右边的 1 被清除,就会导致 精度缺失 。

举一个实际的例子来说明一下,假设 A=1.625×23=1.1012×23 , B=1.75×21=1.112×21 ,在计算 A+B 时,使用以下步骤:
- 对阶 :低位向高位, B=0.01112×23 。
- 尾数相加 : A+B=(1.1012+0.01112)×23=10.00012×23
- 尾数规格化 : 10.00012×23=1.00001×24
相关笔记
- 概论
- 计算机性能指标
- 计算机系统层次结构