Skip to content

浮点数表示(IEEE 754)

2026 大纲 二(四)1 浮点数的表示:IEEE 754 标准

32 位怎么分,决定了这一节的全部内容

浮点数的定义只有一行:

N=(1)S×M×2E

但真正决定一切的是这 32 位(或 64 位)怎么分给 SEM 三个字段——因为 1+k+m 是定死的:

🔴 阶码定范围、尾数定精度,两者在同一份预算里抢位置。 这就是浮点数所有权衡的源头:想要更大的范围就得多给阶码几位,代价是尾数变短、精度下降。后面讲的范围、精度、能不能精确表示、怎么舍入,全都从这一句往下推。

分配之外还有两个设计决定,各自解释了一整类现象。第一个是阶码用移码

🔴 两条理由——① 加偏置后真值的顺序被原样保留,于是(同号时)整个位串按无符号整数比大小就是数值大小,硬件可以直接比;② 移码下的全 0 与全 1 恰好是指数的两个端点,把它们征用来表示特殊值,只切掉数轴的末梢。⚠️ 偏置常数是 2k11(单精度 127、双精度 1023),不是 2k1

第二个是隐藏位

🔴 二进制规格化尾数的最高位恒为 1,所以不存它。23 位字段因此能表示 24 位有效数字(双精度 52 → 53)。代价是这个格式表示不出 0——整张特殊值表就是被这个代价逼出来的。

⚠️ 顺带记一条:尾数用原码,符号单独放在 S 位,尾数字段只存绝对值的小数部分、不取反加 1。所以浮点数取负只需翻转 S 位,一位尾数都不用动

交互可视化

加载可视化中...
加载可视化中...

一、字段划分

字段单精度 float(32 位)双精度 double(64 位)
符号 S1 位,[31]1 位,[63]
阶码 E8 位,[30:23]11 位,[62:52]
尾数 f23 位,[22:0]52 位,[51:0]
偏置常数 bias271=1272101=1023
有效位数24 位(含隐藏位)53 位(含隐藏位)
规格化数的指数范围126+1271022+1023

规格化要求尾数写成 1.f:小数点前恰好一位非零数字。二进制下非零数字只有 1 一种可能,所以这一位恒为 1,存它是纯粹的浪费——IEEE 754 把它省掉,读的时候自动补回 1.

真值=(1)S×1.f×2Ebias

白赚一位精度,欠下的是 1.f1 恒成立,这个格式表示不出 0

二、五类取值

阶码 E尾数 f含义真值
全 0=0±0正零、负零,比较时相等
全 00非规格化数(1)S×0.f×21bias
全 1=0±1/0
全 10NaN10/0
12k2任意规格化数(1)S×1.f×2Ebias

所以单精度规格化数的真实指数是 1127=126254127=+127

这张表有三处最容易记岔:

🔴 阶码全 0 不等于 0,全 1 不等于 。阶码只决定走哪条分支,尾数决定分支内取什么:全 0 且尾数全 0 才是 ±0,尾数不全 0 是非规格化数;全 1 且尾数全 0 才是 ±,不全 0 是 NaN

🔴 非规格化数的指数是 1bias,单精度是 126 不是 127 记法:它与最小规格化数共用同一个指数,区别只在隐藏位一个是 0、一个是 1。

🔴 有效位是 24 位不是 23 位,差的那一位是隐藏位。而且只有规格化数才有隐藏位 1,非规格化数的隐藏位是 0——前导零越多有效数字越少,这正是非规格化区精度逐渐退化的原因。

这张表不是五条规则,是从"0 表示不出来"一路推出来的(想弄清为什么征用的是阶码全 0、非规格化数的指数为什么必须取 1-bias 时展开)

先给"阶码定范围、尾数定精度"一点量纲感。 定点数把全部位都用来存有效数字,位权是固定的:想表示 1030 就得摆出上百位,想表示 1030 又得往小数端摆上百位。而实际计算里一个数往往只需要六七位有效数字,真正变化剧烈的是量级。浮点数把"量级"和"有效数字"分开存,于是同样 32 位,定点整数只能覆盖 ±231,单精度浮点能覆盖 ±1038——代价就是这两部分要在同一份预算里抢位置。

推导链

  1. 隐藏位使 1.f10 表示不出来 必须征用一个位串专门表示 0。
  2. 征用哪个?移码下只能从数轴末梢下手,于是取阶码全 0。为了让 ±0 都有编码,规定阶码全 0 尾数全 0 时为 ±0,符号由 S 决定。
  3. 阶码全 0 被征用后,尾数不全 0 的那些位串(2231 个)就闲置了。丢掉可惜——把它们改成"隐藏位为 0"来解释,即 0.f,正好能表示比最小规格化数还小的一批数,称为非规格化数
  4. 数轴一端征用了,另一端(阶码全 1)对称地拿去表示"超出范围"和"没有定义":尾数全 0 表 ±,尾数不全 0 表 NaN
  5. 剩下的阶码 12k2 才是规格化数。

非规格化数的指数为什么是 1bias 阶码字段是全 0,按常规解码应得 0127=127,但标准规定它是 126。理由是要与最小规格化数无缝衔接

最大非规格化数(指数取 126(1223)×2126
最小规格化数1.0×2126
两者之差223×2126=2149
相邻非规格化数之间的间隔223×2126=2149

后两行完全相等——从非规格化区跨到规格化区,数的疏密没有任何跳变。如果指数取 127,最大非规格化数只有约 0.5×2126,与最小规格化数之间会留下一个宽度约 2127空洞,比该处相邻数的间隔大了 222 倍。

非规格化数存在的全部意义就是填补 0 到最小规格化数之间的空隙,让下溢变成"渐进"的而不是"一步归零"。指数取 1bias 是让这个填补严丝合缝的唯一取值。

与 NaN 为什么要分开。 表示结果超出了范围但方向确定,参与后续运算仍有意义(5+=);NaN 表示结果根本没有定义0/01 说不出是正是负)。合并成一种,5+(+) 就给不出确定结果了。分开的收益是:程序遇到溢出可以继续算,遇到无定义才需要中断。

三、阶码为什么用移码

阶码要能表示负指数,必须是带符号编码。候选有原码、补码、移码,理由有两条,第二条更决定格式设计。

理由一:比大小可以直接按位串比。 移码是"真值加偏置常数",加完后真值的顺序被原样保留到无符号整数的顺序里。于是阶码在高位、尾数在低位这样一排,一条整数比较指令就够了。补码做不到——补码里 1 是全 1,按无符号读是最大值,负指数会排到正指数后面去。

理由二:把"两个极端位串"腾到了数轴两端。 IEEE 754 需要一些位串表示 0、NaN,它们必须从原本能表示实数的编码里挖走。挖哪两个:

阶码编码全 0 代表的指数全 1 代表的指数挖走它们等于
补码01在数轴正中间挖两个洞
移码最小指数最大指数只切掉数轴的两个末梢

移码下损失的只是最极端的量级——那个量级本来也接近溢出。换成补码,被挖掉的就是最常用的 2021 附近,格式当场废掉。

偏置常数为什么取 2^{k-1}-1 而不是一般移码的 2^{k-1}(想核对正负指数范围为什么不对称时展开)

全 0 和全 1 被征用后,可用阶码只剩 12k2。偏置取小 1,能让剩下这段正负指数的分布更均衡——单精度实际指数范围是 126+127,正向多一格,因为全 1 被拿走的是正端。

若偏置仍取 128,范围会变成 127+126,负端多一格;两者都不对称,标准选了前者,同时也让最大量级略大一点。

顺带一提基数:有些早期格式基数取 16(如 IBM 370 短浮点数),规格化尾数的最高一位十六进制数码可以是 1F 中任意一个,没有"恒为 1"这回事,隐藏位无从谈起。基数取 2 才有隐藏位,这是 IEEE 754 把基数定死为 2 的收益之一。

四、范围与精度:四个数不要混

问的是单精度的答案怎么来的
最小规格化正数1.0×2126Emin=1e=1127=126,尾数最小是 1.0
最小正数(含非规格化)2149非规格化最小:223×2126
最大正数(2223)×2127=21282104Emax=254e=127,尾数最大是 1.111=2223
能精确表示的最大整数224有效位只有 24 位,224+1 就已经存不下了

超过 224 之后,浮点数仍然"表示得出"更大的整数,只是表示得不精确224225 之间只能表示偶数。

这张表里的四个数最容易互相串,两组区别要盯死:

🔴 "能表示"与"能精确表示"是两个问题。 最大正数 21282104阶码决定;能精确表示的最大整数 224尾数决定——224+1 会被静默地存成 224。问法里"精确"这两个字必须逐字读。

🔴 最小正数与最小规格化正数差 22321492126),差的正是整个非规格化区。题面里有没有"规格化"三个字,答案差七个数量级。

由此得到的选型判据:先看范围够不够(n 位补码整数是 [2n1,2n11]),再看精度够不够(单精度 24 位有效位、双精度 53 位)。范围装得下就用整型——精确且运算快,只有装不下才考虑浮点,此时还要回头检查有效位数。例如某量可达 ±240:32 位整数装不下,单精度范围够但只有 24 位有效位存不准,必须用双精度

int 与 float 相互转换时具体丢什么,见 C 语言中的数据类型与转换

五、哪些数能被精确表示

判据只有一条:一个十进制小数能用有限位二进制小数精确表示,当且仅当它化成最简分数后,分母是 2 的幂。

最简分数分母能否精确表示
2.02/11=20
2.55/221
1.255/422
0.43757/1624
1.26/55
0.11/1025

分母里只要含有 2 以外的质因子(5、3……),二进制展开就是无限循环的,只能截断存储。这就是 0.1 + 0.2 != 0.3 的根源。

六、舍入

模式规则别名
就近舍入(中间值取偶)舍到最近的可表示数;正好在两个可表示数正中间时,取尾数末位为 0(偶数)的那个默认模式
+ 舍入总取数轴上右边那个可表示数正向舍入、朝上舍入
舍入总取数轴上左边那个可表示数负向舍入、朝下舍入
0 舍入直接截断丢弃多余位,取更靠近原点的那个截断、恒舍法

二进制下"是不是正中间"有一条机械判据——只看被丢弃的那串位:

被丢弃位串与半个末位比怎么做
0…不足一半,保留位不动
1… 且后面还有 1超过一半,保留位加 1
1 000…0(首位 1、其后全 0)恰好一半取偶:保留位末位是 1 就加 1,是 0 就不动

🔴 "取偶"这一条极少触发。 只有被丢弃的部分恰好是半个末位(首位 1、其后全 0)时才用它,其余情况就是普通的 0 舍 1 入。所以顺序是先判"是不是正中间",再决定用哪条——反过来先想着取偶,就会算错。

舍入位 R 与粘位 S:判据只要两个信号,以及"取偶"的唯一理由(想弄清进位公式与硬件为什么不必留下整串丢弃位时展开)

演示(尾数只保留 4 位,就近舍入):

原尾数保留位丢弃位判定结果
1.0110 010001100100首位 0 → 舍0110
1.0110 110001101100首位 1 且后有 1 → 入0111
1.0110 100001101000恰好一半,末位 0 → 不动0110
1.0111 100001111000恰好一半,末位 1 → 加 11000

后两行的丢弃位完全相同,只因保留位末位的奇偶不同,处理就相反——"取偶"只在这两行生效

上表的三行判定实际只用到被丢弃位串的两个信息:

  • 舍入位 R:紧挨保留位的第一个被丢弃位
  • 粘位 S:其余所有被丢弃位的逻辑或("后面还有没有 1")

设保留位末位为 L,则

进位R(S+L)

R=0 一律舍;R=1S=1 一律入;R=1,S=0 是"恰好一半",此时由 L 定夺(L=1 才进位),正是取偶。这解释了为什么硬件不必保存全部被丢弃的位:无论丢掉多少位,只要一个 R 和一个 S 就够了S 用一个"只要来过 1 就永久置 1"的粘滞触发器累积,名字即由此而来。

为什么"中间值取偶"而不是统一进位:统一"逢中进位"会让误差单向累积——每次都往大的一侧偏,一长串运算下来结果系统性偏高。取偶让中间值一半向上、一半向下(末位是 0 还是 1 大致各半),误差期望为 0。这是"取偶"唯一的理由,与位模式好不好看无关。

七、怎么比大小

移码阶码的设计就是为了这件事:

  1. 先看符号位S=0 的一定大于 S=1 的(±0 除外)。
  2. 同为正数:直接把整个 32 位当无符号整数比——阶码在高位、尾数在低位,字典序正好等于数值序。
  3. 同为负数反过来——位模式作为无符号数越大,绝对值越大,值反而越小。

第 3 条最容易翻车。稳妥的做法是把两个数的符号和真实指数都写出来再下结论。

🔴 负浮点数比大小要反过来。 正数把整个位串当无符号整数直接比就行;负数的位模式越大,值反而越小±0 与 NaN 是这条捷径的两个例外——特别是 NaN 与包括它自己在内的任何数比较都不相等

两个方向的转换各走一遍,外加 2^24+1 存不下的全过程(想核对自己的转换步骤或舍入判据用得对不对时展开)

机器数 → 真值:十六进制展开成 32 位 → 按 1 / 8 / 23 切开 → 先看阶码是不是全 0 或全 1(这一步决定走哪条公式)→ 规格化数取 e=E127、尾数前补回隐藏位 1. → 写成 (1)S×1.f×2e

真值 → 机器数:绝对值写成二进制 → 规格化成 1.xxx×2eE=e+127 转 8 位二进制 → 小数点后的位填进尾数字段、右边补 0 补满 23 位 → 拼成 32 位再四位一组转十六进制。

常用二进制小数0.5=0.120.25=0.0120.125=0.00120.0625=0.000120.375=0.01120.4375=0.011120.75=0.112。把要转的小数拆成这几个的和,比反复乘 2 快得多。

(一)机器数 → 真值:某单精度机器数为 C154 0000H。展开成 1 10000010 10101000000000000000000S=1 为负;E=100000102=130,既不全 0 也不全 1,属规格化数,e=130127=3;尾数补回隐藏位得 1.101012=1.65625

x=1.65625×23=13.25

反向验算:13.25=1101.012=1.101012×23

(二)真值 → 机器数:把 +65.5 写成单精度。65.5=1000001.12=1.0000011×26E=6+127=133=100001012;尾数字段取小数点后并右补 0 满 23 位。拼成 0 10000101 00000110000000000000000

01004 00102 10008 00113 000000000000=4283 0000H

(三)16777217(即 224+1)装不下时怎么办,正好走一遍舍入判据。

  1. 二进制:224+1=100000000000000000000000125 
  2. 规格化:1.0000000000000000000000023 位,全 01×224——小数点后需要 24 位才写得全,而尾数字段只有 23 位,多出来的正是末尾那个 1
  3. 套判据:丢弃部分是 1首位为 1 且其后再无 1,属恰好一半;保留部分末位是 0(偶),故不进位
16777217 就近舍入到偶数 16777216=224
  1. 阶码 E=24+127=151=100101112,尾数字段全 0,得 4B80 0000H

4B80 0000H 读回来得到的是 16777216——这个整数被静默地改掉了。这也是 intfloat 会丢精度的原因:两者同为 32 位,但 float 拿走 8 位存量级,留给有效数字的反而更少。

三问走的是同一条路。每次都先看阶码是不是全 0 或全 1——这一步决定用规格化公式还是非规格化公式。

考点速记

  1. 总位数定死,阶码定范围、尾数定精度;阶码用移码,既让位串顺序等于数值顺序,又把待征用的全 0 / 全 1 推到数轴两端,偏置常数取 2k11(127 / 1023)。
  2. 二进制规格化尾数最高位恒为 1 故隐藏不存(23 位字段 → 24 位有效数字),代价是表示不出 0,由此逼出整张五类取值表:阶码只决定走哪条分支,尾数决定分支内的取值非规格化数的指数固定为 1bias(单精度 126),与最小规格化数共用同一个指数。
  3. "能表示"由阶码决定、"能精确表示"由尾数决定(最大正数 21282104 vs 最大精确整数 224);能精确表示 最简分数的分母是 2 的幂;就近舍入只有恰好半个末位时才取偶负浮点数比大小要反过来

这一节在真题里被考过的形式(下方「真题练习」逐题对应,本章题量最大的一篇):

  • 给一个十六进制机器数,问它按 float 解释的值:展开成 32 位 → 按 1/8/23 切开 → 先看阶码是不是全 0 或全 1(决定走哪条公式)→ 规格化数取 e=E127、尾数前补回 1.
  • 给一个十进制数,问它的 float 机器数:绝对值转二进制 → 规格化成 1.xxx×2eE=e+127 → 尾数右边补 0 补满 23 位 → 四位一组转十六进制。
  • 问单精度能表示的最小/最大正数,或能精确表示的最大整数:四个数各有各的来源,看清题面有没有"规格化""精确"这两组字——最小正数 2149 与最小规格化正数 2126223 倍,最大正数由阶码定而最大精确整数 224 由尾数定。
  • 问某个 int 值转成 float 后是否精确、或两个类型能否互相无损往返:比有效位数——int 有效位可达 31 位、float 只有 24 位,超过 224 的奇数存不下。
  • 给一个机器数,问它按 int 或按 float 解释时的值可能是多少:同一串位分别按补码和 IEEE 754 各读一遍。
  • 挑关于 IEEE 754 的错误叙述:常设的错点是"阶码全 0 表示 0""偏置常数是 2k1""有效位是 23 位""非规格化数的指数是 127"——四条全是本篇 🔴 标出来的那几处。
  • 大题里做浮点数的编码与解码:步骤同上两条,但要写出每一步的中间结果(阶码字段的十进制值、尾数补隐藏位后的形式),只给最终答案通常拿不到全分。

易错:把偏置常数记成 2k1。是 2k11

易错:非规格化数的指数按 Ebias 算成 127。它固定是 1bias

易错:有效位按尾数字段的 23 位算。加上隐藏位是 24 位。

易错:把"最小正数"与"最小规格化正数"混答。差整个非规格化区。

易错:负浮点数按位串顺着比大小。要反过来。

教材出处
  • IEEE 754 格式、隐藏位、偏置常数取 2n11 的两个好处:袁春风《计算机组成与系统结构》第 3 版 §2.3.3 IEEE 754 浮点数标准,印刷页 p36
  • 五类取值的解释(表 2.2)、非规格化数指数固定为 126/1022 且用于处理阶码下溢、NaN 的产生操作(表 2.3)、格式参数(表 2.4):同书 §2.3.3,印刷页 p37–p38
  • 浮点数规格化的定义与左规/右规:同书 §2.3.2 浮点数的规格化,印刷页 p36
  • 基数为 16 的浮点格式(IBM 370 短浮点数,尾数用十六进制原码小数、无隐藏位)与基数为 2 的格式对照:同书 §2.3.1 浮点数的表示格式 例 2.21/例 2.22,印刷页 p35
  • 四种舍入方式及表 3.4 舍入示例、图 3.17 浮点数间隔(数密度):同书 §3.5.2 浮点运算的精度和舍入,印刷页 p83–p85
  • 单精度最小可表示数 223×2126=2149、规格化数个数与量级范围:袁春风《计算机系统基础》§2.3.3,印刷页 p49

相关知识

真值与机器数:四种编码的定义浮点数的加减运算C 语言中的数据类型与转换进位计数制与转换

真题练习