1. 原码
原码是一种计算机中对数字的二进制定点表示法。原码表示法在数值前面增加了一位符号位(即最高位为符号位):正数该位为 0,负数该位为 1(0 有两种表示:+0 和 -0),其余位表示数值的大小。举个例子,我们用 8 位二进制表示一个数,+12
的原码为 00001100
,-12
的原码就是 10001100
。
2. 反码
一个数字用原码表示是容易理解的,但是需要单独一个位来表示符号位,并且在进行加法时,计算机需要先识别某个二进制原码是正数还是负数,识别出来之后再进行相应的运算。这样效率不高,能不能让计算机在进行运算时不用去管符号位,也就是让符号位参与运算。要实现这个功能,我们就要用到反码。
2.1 反码规则
反码是一种在计算机中数的机器码表示。对于单个数值(二进制的 0 和 1)而言,对其进行取反操作就是将 0 变为 1,1 变为 0。
- 正数的反码和原码一样。
- 负数的反码就是在原码的基础上符号位保持不变,其他位取反。
例如:
十进制 | 原码 | 反码 |
---|---|---|
6 | 0000 0110 | 0000 0110 |
-3 | 1000 0011 | 1111 1100 |
2.2 直接用反码计算减法有什么问题?
-
- 用反码直接算
6-3
- 用反码直接算
6 - 3 ==> 6 + (-3)
0000 0110 // 6(反码)
+ 1111 1100 // -3(反码)
----------------------
0000 0010 // (反码)
0000 0010 // 2(原码)
显然计算错误
-
- 用反码直接算
1-1
- 用反码直接算
1 - 1 ==> 1 + (-1)
0000 0001 // 1(反码)
+ 1111 1110 // -1(反码)
----------------------
1111 1111 // (反码)
1000 0000 // -0(原码)
由上可知 1 + (-1)
的运算结果为 -0
,而我们预期的值是 +0
。
-
- 用反码计算
0 + 0
- 用反码计算
0 + 0 ==> 0 + 0
0000 0000 // 0(反码)
+ 0000 0000 // 0(反码)
----------------------
0000 0000 // (反码)
0000 0000 // 0(原码)
这里我们可以知道 -0
对应的原码是 1000 0000
,而 +0
对应的原码是 0000 0000
。虽然 -0
和 +0
代表的数值是一样的,但是在用原码和反码表示时它们是不同的。通过以上的多个示例,我们发现使用反码进行加法运算并不能保证得出正确的结果。原因是用一个字节表示数字的取值范围时,这些数字中多了一个 -0
。为了解决反码出现的问题,就出现了补码。
3. 补码
补码是一种用二进制表示有符号数的方法。
- 正数和 0 的补码就是该数字本身。
- 负数的补码则是将其对应正数按位取反再加 1。
3.1 补码的优点
- 补码系统的最大优点是可以在加法或减法处理中,不需因为数字的正负而使用不同的计算方式。只要一种加法电路就可以处理各种有符号数加法,而且减法可以用一个数加上另一个数的补码来表示,因此只要有加法电路和补码电路即可以完成各种有符号数加法和减法,在电路设计上相当方便。
- 补码系统的 0 就只有一个表示方式,这和反码系统不同(在反码系统中,0 有两种表示方式),因此在判断数字是否为 0 时,只要比较一次即可。下图是一些 8 位补码系统的整数,它可表示的范围包括 -128 到 127,总共 256 个整数。
3.2 补码计算
十进制 | 原码 | 反码 | 补码 |
---|---|---|---|
6 | 0000 0110 | 0000 0110 | 0000 0110 |
-3 | 1000 0011 | 1111 1100 | 1111 1101 |
6 - 3 ==> 6 + (-3)
0000 0110 // 6(补码)
+ 1111 1101 // -3(补码)
----------------------
0000 0011 // 3(补码)
1 - 1 ==> 1 + (-1)
0000 0001 // 1(补码)
+ 1111 1111 // -1(补码)
----------------------
0000 0000 // 0(补码)