定点数的加减运算
补码加减法的运算规则只有一行,简单得不像考点:
真正的考点全在这一行之外:算出来的位串,什么时候不能信。加法器永远给出一个结果,它从不拒绝计算——判断这个结果有没有意义,是标志位和溢出判据的工作。
机制
规则:符号位一起参与运算,进位自然丢弃
补码加法不区分符号位和数值位,整个
这条规则的合法性来自模运算:
减法完全不需要新规则,转成”加相反数”即可,硬件实现见 2.2.1 加减统一电路。
原码加减法之所以被淘汰,对比之下很清楚:原码相加要先判断两数符号是否相同,同号则绝对值相加、异号则比较绝对值大小、大的减小的、结果符号取绝对值大的那个。光是”比较绝对值”就要额外做一次减法,控制逻辑比补码复杂一个量级。
溢出:三种等价判据
溢出的定义只有一个:真值结果超出了该编码在该字长下的表示范围。判据有三种写法,答案永远一致,选哪个看题目给了什么。
判据一:符号法——只有同号相加才可能溢出,且结果符号与之相反。
判据二:进位法——最高位进位与次高位进位不同即溢出。
这是硬件实际采用的判据,因为它只需一个异或门,且两个信号加法器本来就有。
判据三:双符号位法(变形补码 / 模 4 补码)——两个符号位不同即溢出。
把符号位复制成两位,按模
| 双符号位 | 含义 |
|---|---|
00 | 正数,正常 |
11 | 负数,正常 |
01 | 正溢出(上溢) |
10 | 负溢出(下溢) |
这两位各自的含义要分清,否则极易记反:
- 高位符号位是结果的真正符号(模
下没有被挤坏); - 低位符号位是”只用一位符号位时会看到的那个表面符号”。
于是 01 读作”真符号为正、表面符号为负”——真值是正的,却因为超出范围而在单符号位下显示成负数,这就是上溢。10 反之,是下溢。
验证一遍(定点小数,模 4):00.1011 + 00.0111 = 01.0010。真值
两位符号位是否相同,等价于判据二的
三种判据的关系:判据一是定义,判据二是它的电路实现,判据三是它的手算形式。
标志位
一次加减法之后,机器同时产生四个标志位,它们是互相独立的四个事实,不是四选一:
| 标志 | 名称 | 含义 | 服务于 |
|---|---|---|---|
| CF | 进位/借位 | 无符号解释 | |
| OF | 溢出 | 有符号解释 | |
| ZF | 零 | 结果全 0 时为 1 | 两者通用 |
| SF | 符号 | 结果的最高位 | 有符号解释 |
CF 的公式里那个
同一次加法的两种解释
这张表是本节最该吃透的东西,它把 2.1.3 “硬件不区分有无符号”落到了具体数字上。全部按 8 位补码加法器:
| 运算 | 结果 | CF | OF | ZF | SF | 无符号解释 | 有符号解释 | ||
|---|---|---|---|---|---|---|---|---|---|
0x7F + 0x01 | 0x80 | 0 | 1 | 0 | 1 | 0 | 1 | ||
0xFF + 0x01 | 0x00 | 1 | 1 | 1 | 0 | 1 | 0 | ||
0x80 + 0x80 | 0x00 | 1 | 0 | 1 | 1 | 1 | 0 | ||
0x40 + 0x20 | 0x60 | 0 | 0 | 0 | 0 | 0 | 0 |
前两行是关键:第一行 CF=0 而 OF=1,第二行 CF=1 而 OF=0。同一串位、同一个加法器,无符号视角和有符号视角给出的”对错”判断完全相反。
机器并不知道该看哪一个——是编译器根据变量类型选择了不同的条件跳转指令(ja/jb 看 CF,jg/jl 看 OF 和 SF)。这正是 C 里”有符号溢出是未定义行为、无符号回绕有定义”的机器层背景。
无符号数的溢出为什么看 CF
无符号数没有符号位,
减法则相反:
所以无符号比较大小就是做一次减法看 CF:cmp A, B 后 CF=1 说明
边界
CF 与 OF:最高频的混淆
| CF | OF | |
|---|---|---|
| 来自 | ||
| 回答 | 无符号结果对不对 | 有符号结果对不对 |
| 加法器需要额外硬件吗 | 不需要,进位天然存在 | 需要一个异或门 |
“最高位有进位”和”溢出”是两件不同的事,上表第二行 0xFF + 0x01 就是反例:有进位(CF=1),但有符号结果
判据:进位是”位串装不下”,溢出是”符号被改变”。
异号相加不溢出,同号相减不溢出
由判据一直接得出,这两条能省掉一半的判断工作:
- 加法:只有同号相加才可能溢出。
- 减法:转成加相反数后,只有异号相减才可能溢出(
中 或 )。
溢出之后结果是什么
结果不是随机的,也不是”截断”——它就是数学真值对
机器不会因为溢出而停下来(除法是例外,见 2.2.4)。它只置位 OF,然后继续执行。是否处理,由程序决定——这一点与异常机制的关系是:x86 提供 INTO 指令,可在 OF=1 时主动触发一个陷阱,但编译 C 代码时并不生成它。
双符号位不是”多用一位”
变形补码在运算过程中用两位符号位,存储时仍然只用一位。它是一种手算/中间寄存器的技巧,不改变数据的存储格式。
用双符号位时模是
对照速查
| 溢出判据 | 写法 | 场合 |
|---|---|---|
| 符号法 | 同号相加、结果异号 | 定义,理解用 |
| 进位法 | 硬件实现,做题最快 | |
| 双符号位 | 01 上溢 / 10 下溢 | 手算、变形补码题 |
| 标志 | 公式 | 谁在用 |
|---|---|---|
| CF | 无符号 | |
| OF | 有符号 | |
| ZF | 结果全 0 | 通用 |
| SF | 结果最高位 | 有符号 |
考点
- 补码加减的符号位参与运算,进位丢弃,合法性来自模
- 三种溢出判据等价:同号相加结果异号 /
/ 双符号位不同 - 双符号位
01是上溢,10是下溢 - CF 服务无符号,OF 服务有符号;
0xFF+0x01是 CF=1、OF=0 的标准反例 - 减法时 CF 是借位标志,因为
- 异号相加不溢出;异号相减才可能溢出
- 溢出后结果是模
的值,机器不中断 - 无符号比较大小 = 做减法看 CF
链接
- 🏠 返回总览:计算机组成原理第 2 章:数据的表示和运算总览
- ⬅️ 上一节:2.2.2 定点数的移位运算
- ➡️ 下一节:2.2.4 定点数的乘除运算
- 📖 名词库:第 2 章名词库