定点数的加减运算

补码加减法的运算规则只有一行,简单得不像考点:

补补补补补补

真正的考点全在这一行之外:算出来的位串,什么时候不能信。加法器永远给出一个结果,它从不拒绝计算——判断这个结果有没有意义,是标志位和溢出判据的工作。

机制

规则:符号位一起参与运算,进位自然丢弃

补码加法不区分符号位和数值位,整个 位一起送进加法器,最高位产生的进位直接丢弃。

这条规则的合法性来自模运算: 位加法器本身就是模 的运算器,而补码正是按模 定义的。丢弃进位不是”忽略错误”,而是取模这个动作本身。

减法完全不需要新规则,转成”加相反数”即可,硬件实现见 2.2.1 加减统一电路。

原码加减法之所以被淘汰,对比之下很清楚:原码相加要先判断两数符号是否相同,同号则绝对值相加、异号则比较绝对值大小、大的减小的、结果符号取绝对值大的那个。光是”比较绝对值”就要额外做一次减法,控制逻辑比补码复杂一个量级。

溢出:三种等价判据

溢出的定义只有一个:真值结果超出了该编码在该字长下的表示范围。判据有三种写法,答案永远一致,选哪个看题目给了什么。

判据一:符号法——只有同号相加才可能溢出,且结果符号与之相反。异号相加绝不溢出,这一点值得单独记:异号相加的结果的绝对值必然不超过两者中较大的那个,一定在范围内。减法要先转成加法再套用—— 是 ,所以”异号相减”才可能溢出。

判据二:进位法——最高位进位与次高位进位不同即溢出。, 是符号位产生的进位, 是数值最高位向符号位的进位。两者相等意味着符号位收到的和送出的一致,符号没有被数值”挤坏”;不等则说明数值部分的进位改变了符号位,结果不可信。

这是硬件实际采用的判据,因为它只需一个异或门,且两个信号加法器本来就有。

判据三:双符号位法(变形补码 / 模 4 补码)——两个符号位不同即溢出。

把符号位复制成两位,按模 运算。结果的两位符号位:

双符号位含义
00正数,正常
11负数,正常
01正溢出(上溢)
10负溢出(下溢)

这两位各自的含义要分清,否则极易记反:

  • 高位符号位是结果的真正符号(模 下没有被挤坏);
  • 低位符号位是”只用一位符号位时会看到的那个表面符号”。

于是 01 读作”真符号为正、表面符号为负”——真值是正的,却因为超出范围而在单符号位下显示成负数,这就是上溢。10 反之,是下溢。

验证一遍(定点小数,模 4):,即 00.1011 + 00.0111 = 01.0010。真值 已超过 ,高位符号 0 说明真值为正,判为上溢,与实际一致。

两位符号位是否相同,等价于判据二的 ——它们本来就是同一个异或。

三种判据的关系:判据一是定义,判据二是它的电路实现,判据三是它的手算形式。

标志位

一次加减法之后,机器同时产生四个标志位,它们是互相独立的四个事实,不是四选一:

标志名称含义服务于
CF进位/借位无符号解释
OF溢出有符号解释
ZF零结果全 0 时为 1两者通用
SF符号结果的最高位有符号解释

CF 的公式里那个 值得解释:做加法时(), 表示产生了进位;做减法时(),加法器算的是 , 恰恰表示”没有借位”(够减),所以要取反才是借位标志。这就是”减法时 CF 是借位标志”的由来。

同一次加法的两种解释

这张表是本节最该吃透的东西,它把 2.1.3 “硬件不区分有无符号”落到了具体数字上。全部按 8 位补码加法器:

运算结果CFOFZFSF无符号解释有符号解释
0x7F + 0x010x80010101,正确,溢出
0xFF + 0x010x00111010,溢出,正确
0x80 + 0x800x00101110,溢出,溢出
0x40 + 0x200x60000000,正确,正确

前两行是关键:第一行 CF=0 而 OF=1,第二行 CF=1 而 OF=0。同一串位、同一个加法器,无符号视角和有符号视角给出的”对错”判断完全相反。

机器并不知道该看哪一个——是编译器根据变量类型选择了不同的条件跳转指令(ja/jb 看 CF,jg/jl 看 OF 和 SF)。这正是 C 里”有符号溢出是未定义行为、无符号回绕有定义”的机器层背景。

无符号数的溢出为什么看 CF

无符号数没有符号位, 位的合法范围是 。结果超出这个范围,唯一的表现就是产生了第 位,即 。

减法则相反: 在 时结果为负,无符号无法表示,表现为借位,即 (取反后 CF=1)。

所以无符号比较大小就是做一次减法看 CF:cmp A, B 后 CF=1 说明 。

边界

CF 与 OF:最高频的混淆

CFOF
来自(最高位进位)
回答无符号结果对不对有符号结果对不对
加法器需要额外硬件吗不需要,进位天然存在需要一个异或门

“最高位有进位”和”溢出”是两件不同的事,上表第二行 0xFF + 0x01 就是反例:有进位(CF=1),但有符号结果 完全正确(OF=0)。

判据:进位是”位串装不下”,溢出是”符号被改变”。

异号相加不溢出,同号相减不溢出

由判据一直接得出,这两条能省掉一半的判断工作:

  • 加法:只有同号相加才可能溢出。
  • 减法:转成加相反数后,只有异号相减才可能溢出( 中 或 )。

溢出之后结果是什么

结果不是随机的,也不是”截断”——它就是数学真值对 取模后按补码解释的值。 得到 ,因为 。

机器不会因为溢出而停下来(除法是例外,见 2.2.4)。它只置位 OF,然后继续执行。是否处理,由程序决定——这一点与异常机制的关系是:x86 提供 INTO 指令,可在 OF=1 时主动触发一个陷阱,但编译 C 代码时并不生成它。

双符号位不是”多用一位”

变形补码在运算过程中用两位符号位,存储时仍然只用一位。它是一种手算/中间寄存器的技巧,不改变数据的存储格式。

用双符号位时模是 ,这也是它被称为”模 4 补码”的原因(对定点小数而言模为 4)。

对照速查

溢出判据写法场合
符号法同号相加、结果异号定义,理解用
进位法硬件实现,做题最快
双符号位01 上溢 / 10 下溢手算、变形补码题
标志公式谁在用
CF无符号
OF有符号
ZF结果全 0通用
SF结果最高位有符号

考点

  • 补码加减的符号位参与运算,进位丢弃,合法性来自模
  • 三种溢出判据等价:同号相加结果异号 / / 双符号位不同
  • 双符号位 01 是上溢,10 是下溢
  • CF 服务无符号,OF 服务有符号;0xFF+0x01 是 CF=1、OF=0 的标准反例
  • 减法时 CF 是借位标志,因为
  • 异号相加不溢出;异号相减才可能溢出
  • 溢出后结果是模 的值,机器不中断
  • 无符号比较大小 = 做减法看 CF

链接