原码、反码和补码使用的有无符号的前提说明及相关运算
1. 基本前提
在谈论原码、反码和补码之前,有一个基本大前提,那就是:必须是对于有符号数而言的,无符号数没有原码、反码和补码。即举个例子,如一个问题直接问:求二进制整数1010 1011B的补码,那么这个问题的前提,就是这个数是一个有符号的整数,最高位就表示符号位,0表示正数,1表示负数,从而就不会遇到分不清这个数是正数还是负数而不知道如何求其补码的问题了。
另外,需要明确原码、反码和补码是为了计算机的计算而规定的规则,所以它们的使用必须满足计算机中对数字存储的基本规则。通常一个值的存储最少是以字节(8位,char) 为单位存储的,即计算机中存储一个数值所使用的最小存储单元是8位二进制数,当然存储更大的数据,还有16位(short),32位(int),64位(long)。计算机中的存储要求就是所有整数数字都必须按照这几种位数存储,高位没有的则用0填充。因此,还需要注意一些问题里写出的二进制数的位数,如一个问题里写到求一个二进制整数1011011B的补码,如果问题中没有明确要求了这个数的字长位数,那么就需要将该数按照前面这几种的存储方式进行存储。由于这个数只写了7位,所以如果按照8位的char类型存储,那么就是0101 1011B,最高位是0,则这个数为正数。当然如果是使用更大的空间存储该数,那么也只是在前面继续填充0,即最前面仍然是0,这个数依然是正数。即如果题目没有明确说明某个数字的二进制位数,那么就需要仔细数一下该数字具体有几位,并只需要按照大于该位数的最小存储空间的位数的形式去表示该数字,观察最高位的数字即可。(当然其实对于不满8位,16位,32位,64位的二进制数,其在存储空间中存储时最高位必定是0,即必定是正数)
2. 求有符号数的原码、反码和补码
2.1 求编码方法
对于一个有符号数,其最高位就表示符号位,0表示正数,1表示负数。
对于正数,其原码、反码和补码都一样,就是该数的二进制表示值。
对于负数(假设用8位字长存储,以带符号的二进制数1010 1011B为例):
- 原码:最高的符号位为1,剩下位表示其绝对值,1010 1011B;
- 反码,就是保持其符号位不变,其它位按位取反,1101 0100B;
- 补码:反码的符号位不变,其它位组成的数在数值上加1,1101 0101B;
- 当知道一个数X的补码,则可以通过 { [ X ] 补 } 补 = [ X ] 原 \{\left[X\right]_\text{补}\}_\text{补}=\left[X\right]_\text{原} {[X]补}补=[X]原。同样按照该例子,当知道补码为1101 0101B,则可以将该编码看作原码按照前面的步骤再求其补码,得到1010 1011B,得到了该数的原码。
2.2 表示范围与特殊情况说明
对于 n n n位字长表示的有符号数字,各编码可以表示的实际数的范围如下:
- 原码: − ( 2 n − 1 − 1 ) ∼ + ( 2 n − 1 − 1 ) -\left(2^{n-1}-1\right)\sim+\left(2^{n-1}-1\right) −(2n−1−1)∼+(2n−1−1);
- 反码: − ( 2 n − 1 − 1 ) ∼ + ( 2 n − 1 − 1 ) -\left(2^{n-1}-1\right)\sim+\left(2^{n-1}-1\right) −(2n−1−1)∼+(2n−1−1)(与原码表示的范围一致);
- 补码: − 2 n − 1 ∼ + ( 2 n − 1 − 1 ) -2^{n-1}\sim+\left(2^{n-1}-1\right) −2n−1∼+(2n−1−1),不含 − 0 -0 −0;
以 n = 8 n=8 n=8位字长为例进行说明。对于8位有符号数字,其可以表示的最大正数为0111 1111B(127D),可以表示的最小的负数为1111 1111B(-127D)。对于正数部分,原码、反码和补码都相同。特殊值说明:
- 0000 0000B(+0) 也按照正数的编码规则,反码和补码都是0000 0000B。即只要最高位是0的带符号的数字,其原码、反码和补码都一致;
- 1000 0000B(-0) ,则需要按照负数的编码规则进行处理,则其反码为1111 1111B,但是该数没有补码;
- -128在8位字长下,只有补码1000 0000B,而没有原码和反码。
3. 编码相关运算法则
3.1 运算法则
实际上在计算机中运算的时候,都是以补码进行计算的。无论是加运算还是减运算,都是使用补码相加的方式,只不过在减运算中,是将后一个减数写为加一个负数,再求负数的补码,即
- 求 X ± Y X \pm Y X±Y,是要求 [ X ± Y ] 补 = [ X ] 补 + [ ± Y ] 补 \left[X \pm Y\right]_\text{补}=\left[X\right]_\text{补}+\left[\pm Y\right]_\text{补} [X±Y]补=[X]补+[±Y]补;
- 在不发生溢出的情况下,根据 [ X ± Y ] 补 \left[X \pm Y\right]_\text{补} [X±Y]补,若原码存在(对于 n n n位字长的带符号数, − 2 n − 1 -2^{n-1} −2n−1无原码和反码,若运算结果为该值的补码,则直接判定为该值即可),则按照 { [ M ] 补 } 补 = [ M ] 原 \{\left[M\right]_\text{补}\}_\text{补}=\left[M\right]_\text{原} {[M]补}补=[M]原的法则再求 [ X ± Y ] 原 \left[X \pm Y\right]_\text{原} [X±Y]原得到结果。
以8位字长带符号的数为例,如
43
+
56
43+56
43+56,
103
−
57
103-57
103−57,
32
−
51
32-51
32−51,
−
28
−
64
-28-64
−28−64,分别用
[
43
]
补
+
[
56
]
补
\left[43\right]_\text{补}+\left[56\right]_\text{补}
[43]补+[56]补,
[
103
]
补
+
[
−
57
]
补
\left[103\right]_\text{补}+\left[-57\right]_\text{补}
[103]补+[−57]补,
[
32
]
补
+
[
−
51
]
补
\left[32\right]_\text{补}+\left[-51\right]_\text{补}
[32]补+[−51]补,
[
−
28
]
补
+
[
−
64
]
补
\left[-28\right]_\text{补}+\left[-64\right]_\text{补}
[−28]补+[−64]补,并将各补码按照无符号数字直接进行计算
0
0
1
0
1
0
1
1
+
0
0
1
1
1
0
0
0
‾
0
1
1
0
0
0
1
1
0
1
1
0
0
1
1
1
+
1
1
0
0
0
1
1
1
‾
(
1
)
0
0
1
0
1
1
1
0
\begin{align*} \underline{\begin{align*} &0~0~1~0~1~0~1~1 \\ +~&0~0~1~1~1~0~0~0 \end{align*}}\\ 0~1~1~0~0~0~1~1 \end{align*}\qquad\qquad\qquad\qquad \begin{align*} \underline{\begin{align*} &0~1~1~0~0~1~1~1 \\ +~&1~1~0~0~0~1~1~1 \end{align*}}\\ (1)~0~0~1~0~1~1~1~0 \end{align*}
+ 0 0 1 0 1 0 1 10 0 1 1 1 0 0 00 1 1 0 0 0 1 1+ 0 1 1 0 0 1 1 11 1 0 0 0 1 1 1(1) 0 0 1 0 1 1 1 0
0
0
1
0
0
0
0
0
+
1
1
0
0
1
1
0
1
‾
1
1
1
0
1
1
0
1
1
1
1
0
0
1
0
0
+
1
1
0
0
0
0
0
0
‾
(
1
)
1
0
1
0
0
1
0
0
\begin{align*} \underline{\begin{align*} &0~0~1~0~0~0~0~0 \\ +~&1~1~0~0~1~1~0~1 \end{align*}}\\ 1~1~1~0~1~1~0~1 \end{align*}\qquad\qquad\qquad\qquad \begin{align*} \underline{\begin{align*} &1~1~1~0~0~1~0~0 \\ +~&1~1~0~0~0~0~0~0 \end{align*}}\\ (1)~1~0~1~0~0~1~0~0 \end{align*}
+ 0 0 1 0 0 0 0 01 1 0 0 1 1 0 11 1 1 0 1 1 0 1+ 1 1 1 0 0 1 0 01 1 0 0 0 0 0 0(1) 1 0 1 0 0 1 0 0
可以得到四个补码结果分别为0110 0011,0010 1110,1110 1101,1010 0100,从而得到原码分分别为0110 0011B(99D),0010 1110B(46D),1001 0011B(-19D),1101 1100B(92D),经计算,所得结果正确。
3.2 溢出判定
对于计算结果是否溢出,有2个如下判定法则:
- 当两个数的符号相反时,即两个数的符号位不同,则结果必定不溢出;
- 当两个数符号相同时,若补码计算的结果的最高位(即进位位的位置)的与第二位(即两个加数的符号位的位置)相同,则不溢出;若不同,则溢出。用如下几个例子简单说明
不溢出, 43 + 56 43+56 43+56, − 28 − 64 -28-64 −28−64,结果的最高位与第二位都是0或都是1,
0 0 1 0 1 0 1 1 + 0 0 1 1 1 0 0 0 ‾ ( 0 ) 0 1 1 0 0 0 1 1 1 1 1 0 0 1 0 0 + 1 1 0 0 0 0 0 0 ‾ ( 1 ) 1 0 1 0 0 1 0 0 \begin{align*} \underline{\begin{align*} &0~0~1~0~1~0~1~1 \\ +~&0~0~1~1~1~0~0~0 \end{align*}}\\ (0)~0~1~1~0~0~0~1~1 \end{align*}\qquad\qquad\qquad\qquad \begin{align*} \underline{\begin{align*} &1~1~1~0~0~1~0~0 \\ +~&1~1~0~0~0~0~0~0 \end{align*}}\\ (1)~1~0~1~0~0~1~0~0 \end{align*} + 0 0 1 0 1 0 1 10 0 1 1 1 0 0 0(0) 0 1 1 0 0 0 1 1+ 1 1 1 0 0 1 0 01 1 0 0 0 0 0 0(1) 1 0 1 0 0 1 0 0
溢出, 57 + 76 57+76 57+76, − 68 − 84 -68-84 −68−84,结果的最高位与第二位不同
0 0 1 1 1 0 0 1 + 0 1 0 0 1 1 0 0 ‾ ( 0 ) 1 1 1 0 1 1 0 1 1 0 1 1 1 1 0 0 + 1 0 1 0 1 1 0 0 ‾ ( 1 ) 0 1 1 0 1 0 0 0 \begin{align*} \underline{\begin{align*} &0~0~1~1~1~0~0~1 \\ +~&0~1~0~0~1~1~0~0 \end{align*}}\\ (0)~1~1~1~0~1~1~0~1 \end{align*}\qquad\qquad\qquad\qquad \begin{align*} \underline{\begin{align*} &1~0~1~1~1~1~0~0 \\ +~&1~0~1~0~1~1~0~0 \end{align*}}\\ (1)~0~1~1~0~1~0~0~0 \end{align*} + 0 0 1 1 1 0 0 10 1 0 0 1 1 0 0(0) 1 1 1 0 1 1 0 1+ 1 0 1 1 1 1 0 01 0 1 0 1 1 0 0(1) 0 1 1 0 1 0 0 0
4. 参考资料
- 杨颂华, 冯毛官, 孙万蓉等. 数字电子技术基础[M]. 第二版. 西安: 西安电子科技大学出版社, 2009: 7-9.