知识点

补码与带符号整数运算

定义

设有 nn 位二进制容器,整数 xx 的取值范围是 −2n−1≤x≤2n−1−1-2^{n-1}\le x\le 2^{n-1}-1。xx 的补码编码规定为:x≥0x\ge 0 时与 xx 的无符号二进制相同;x<0x<0 时取 2n+x2^n+x 的 nn 位二进制。因为 2n+x=2n−∣x∣2^n+x=2^n-|x|,负数的编码相当于从 2n2^n 中减去它的绝对值。

补码也可以按位权读:最高位的权是 −2n−1-2^{n-1},其余位的权仍是正的 2i2^i,即

x=−bn−12n−1+∑i=0n−2bi2i.x=-b_{n-1}2^{n-1}+\sum_{i=0}^{n-2}b_i2^i .

这解释了为什么最高位为1就代表负数,也说明最高位的权不是 −1-1 而是 −2n−1-2^{n-1},这是按位读补码时最容易出错的地方。非负数的补码与无符号编码完全一致;同一串位按哪种规则解释,取决于变量的类型,而不是位串本身。

位宽表示范围编码个数
8位−128∼127-128\sim 127256256
16位−32768∼32767-32768\sim 327676553665536
32位−2147483648∼2147483647-2147483648\sim 21474836472322^{32}

范围在负数一侧多一个数:−2n−1-2^{n-1} 有编码,而 +2n−1+2^{n-1} 没有。8位中1000 0000是 −128-128,1111 1111是 −1-1,0000 0000是0。无符号整数的位权与加法规则见二进制四则运算。

性质

为什么用补码

原码把最高位当符号位、其余位当绝对值。它有两个问题:0有 +0与 -0两种编码,浪费一个编码;做减法要先比较绝对值大小、再决定符号,电路无法与加法共用。

补码把这套判断省掉:0只有一种编码,且 A−B=A+(−B)A-B=A+(-B),减法化成加法,只需要一个加法器。代价是表示范围不对称,负数比正数多一个,因为原码里 -0占的位置被 −2n−1-2^{n-1} 占用。

求补码

  1. 确定位宽:按题目给定的位数,或按变量类型取8、16、32位。

  2. 正数直接写:最高位为0,其余位与无符号二进制相同。

  3. 负数取反加一:先写对应正数的 nn 位编码,按位取反,再在末位加1。

位数不足时在左侧补0再取反,取反的结果必须仍是 nn 位;加1产生的进位若超出 nn 位则丢弃。

补码减法

A−BA-B 按 A+(−B)A+(-B) 计算:把 BB 的 nn 位补码取反加一得到 −B-B,再与 AA 相加。结果超出 nn 位的最高进位被丢弃,这一步不是错误,而是模 2n2^n 运算的自然结果。

溢出判断

补码加法只有同号相加才可能溢出:两个正数相加得到负数,或两个负数相加得到正数。异号相加的结果一定落在表示范围内,不会溢出。

证明

设 x>0x>0 且 x<2n−1x<2^{n-1},把 xx 写成 nn 位二进制 bb,记按位取反的结果为 bˉ\bar b。

每一位取反后1与0互换,等价于用全1位串 2n−12^n-1 减去 bb,所以

bˉ=(2n−1)−b.\bar b=(2^n-1)-b .

再加1,得

bˉ+1=2n−b=2n+(−b).\bar b+1=2^n-b=2^n+(-b).

右边正是负数 −b-b 的补码定义,因此取反加一得到的确实是 −x-x 的编码。加1若产生超出第 nn 位的进位,舍弃它不影响低 nn 位的值,而补码本来就只保留 nn 位。

例子

求 −5-5 的8位补码

  1. 写出正数编码:5=(0000 0101)25=(0000\,0101)_2。

  2. 按位取反:1111 1010。

  3. 末位加1:1111 1011。

所以 −5-5 在8位补码中存为1111 1011。按最高位权 −27-2^7 回代检验:

−128+64+32+16+8+0+2+1=−5.-128+64+32+16+8+0+2+1=-5 .

用快速法求 −20-20 的8位补码

20=(0001 0100)220=(0001\,0100)_2,从右往左第一个1在权为 222^2 的那一位。

  1. 保留第一个1及其右边:低三位100不变。

  2. 左边全部取反:0001 0取反得1110 1。

  3. 拼接:得到1110 1100。

结果与取反加一一致。1110 1100按无符号读是236,正好等于 256−20256-20,这也印证了负数编码是 2n−∣x∣2^n-|x|。

用8位补码计算 5−35-3

把减法化成加法:5−3=5+(−3)5-3=5+(-3)。

  1. 写出 55 的补码:0000 0101。

  2. 求 −3-3 的补码:3=(0000 0011)23=(0000\,0011)_2,取反得1111 1100,加1得1111 1101。

把两个编码相加:

0000 0101(5)+  1111 1101(−3)1 0000 0010(258)\begin{array}{rl} 0000\,0101 & (5) \\ +\;1111\,1101 & (-3) \\ \hline 1\,0000\,0010 & (258) \end{array}

两个编码按无符号相加得 258=(1 0000 0010)2258=(1\,0000\,0010)_2。最高位的进位落在第9位,超出8位容器,被丢弃;剩下0000 0010是2,与 5−35-3 一致。

题集

练习

  1. −5-5 的8位补码是 (只填0和1,不写空格)。

    参考解答

    5=(0000 0101)25=(0000\,0101)_2,取反得1111 1010,加1得1111 1011。

  2. 8位补码能表示的整数范围是:

    选择答案
    参考解答

    范围是 −2n−1∼2n−1−1-2^{n-1}\sim 2^{n-1}-1,8位即 −128∼127-128\sim 127。负数多出的那一个编码是1000 0000。

  3. 用8位补码计算 3−53-5,结果的十进制值是 。

    参考解答

    33 的补码是0000 0011,−5-5 的补码是1111 1011。相加得1111 1110,按补码读是 −2-2。

  4. 下列8位补码加法中,会溢出的是:

    题 overflow-cases · choice
    参考解答

    200200 与 −200-200 都超出 −128∼127-128\sim 127;127+1=128127+1=128 同样越界。100+(−100)=0100+(-100)=0 在范围内,不溢出。

  5. −20-20 的8位补码是 (只填0和1,不写空格)。

    参考解答

    用快速法:20=(0001 0100)220=(0001\,0100)_2,保留第一个1及其右边的100,左边0001 0取反得1110 1,拼成1110 1100。

交互探索

同一组位,为什么会有两个值?

切换八个二进制位,对照无符号整数与八位补码的解释。

正在准备演示…