原码
最高位作为符号位:0表示正,1表示负。
其余位表示该数的绝对值。
例如,用8位二进制表示:
+5:绝对值二进制是 101,凑齐8位,符号位0,所以是 0000 0101
-5:绝对值二进制是 101,符号位1,所以是 1000 0101
优点
非常直观,人类容易理解。
缺点
- 存在两个0:+0 (0000 0000) 和 -0 (1000 0000)。这在数学上是没有意义的,而且计算机需要处理两种零(+0和-0),增加复杂性。
- 加减运算复杂:
对于加法:如果是同号,绝对值相加,符号不变;如果是异号,需要比较绝对值大小,然后用大的减小的,结果符号与大的相同。这意味着电路需要设计加法器和减法器两种,且要判断符号,非常麻烦。
反码
为了解决减法问题,人们引入了反码。
定义
- 正数的反码与其原码相同。
- 负数的反码:符号位不变,其余位按位取反(0变1,1变0)。
例如,8位二进制:
+5 的反码:0000 0101
-5 的原码:1000 0101,反码:1111 1010
意图
使用反码,可以将减法转换为加法。原理是:一个数减去另一个数,等于加上这个数的相反数。那么如何表示相反数?就是用反码。
验证
计算 5 - 3,可以转化为 5 + (-3)。
代码登录后可见
这里出现了一个问题:多出来的进位怎么处理?反码的规定是:如果最高位有进位,则要在结果的最低位加1(称为“循环进位”)。
所以,得到 0000 0001 后,再加1,得到 0000 0010,即 2,结果正确。
缺点
- 仍然有两个零:+0 的反码是 0000 0000,-0 的反码是 1111 1111。
- 循环进位增加了电路复杂度。
补码
为了彻底解决两个零和循环进位的问题,补码诞生了。
定义
- 正数的补码与其原码、反码相同。
- 负数的补码:在其反码的基础上加1(丢弃最高位的进位)。
转换步骤(负数)
- 写出该负数的绝对值所对应的二进制(原码)。
- 按位取反(得到反码)。
- 加1(得到补码)。
快捷方法
从右往左扫描原码,遇到第一个1之前(包括这个1)的位保持不变,其余位取反(符号位不变)。这实际上是“取反加1”的另一种实现。
例子
求 -5 的8位补码。
绝对值5的二进制:0000 0101
按位取反:1111 1010 (反码)
加1:1111 1011 (补码)
验证
计算 5 + (-5) 用补码:
代码登录后可见
优点
- 唯一零:0 的补码只有一种表示:0000 0000。而 -0 呢?我们尝试用补码表示 -0:
0的原码:0000 0000
取反:1111 1111
加1:1 0000 0000(进位溢出,丢弃后为 0000 0000),所以和 +0 一样。
- 加减法统一:减法可以转换为加法,不需要额外的电路处理符号,也不需要循环进位。计算机的CPU只需一个加法器就能完成加减运算。
- 表示范围扩展:对于n位二进制,补码能表示的范围是 [-2n-1, 2n-1-1]。例如8位补码范围是 -128 ~ 127。
🚨 注意的要点
- 混淆概念:必须清晰区分原码、反码、补码各自的定义和转换步骤,尤其在处理负数时。
- 补码的范围:对于n位有符号整数(如8位char),补码范围是 -2n-1 到 2n-1-1。例如8位是-128到127,而不是-127到127。-128没有原码和反码,只有补码(1000 0000)。