计算机由0,1组成的数据要如何表示负数有如下三种方式:
- 原码:将整数的最高位设为符号位(为1则为负,为0则为正),剩下的位表示整数的绝对值,其取值范围为
-(2^k-1)-1 ~ +(2^k-1)-1
。 - 反码:将整数的最高位设为符号位(为1则为负,为0则为正),且当表示负数时,将除符号位的所有位数进行反转(即0变为1,1变为0),其取值范围为
-(2^k-1)-1 ~ +(2^k-1)-1
。 - 补码:将整数的最高位设为符号位(为1则为负,为0则为正),且当表示负数时,将正数减1,然后反转每一位,其取值范围为
-(2^k-1) ~ +(2^k-1)-1
。
个人思考:原码有符号位来表示正负足矣了,为什么反码和补码又要反转又要减1呢?以下《计算机体系结构精髓》里的描述。
① 原码,反码和补码每种都有有趣的特性。例如,原码可以创建一个负的零值,即使这个概念不能对应一个有效的数学概念。反码也提供了两个零值:所有位全0和它的补码(所有位全1)。最后,补码正值比负值多了一个(为了容纳零)。
三种表示法至少都被一台计算机使用过。但在硬件架构中补码方案是最常用的
,原因有二:
- 补码使得构建低成本,高速度的硬件执行算术运算成为可能
- 其次,二进制补码算法的硬件也可以处理无符号的算术。
二进制串 | 无符号位权解释 | 原码解释 | 反码解释 | 补码解释 |
---|---|---|---|---|
0000 | 0 | 0 | 0 | 0 |
0001 | 1 | 1 | 1 | 1 |
0010 | 2 | 2 | 2 | 2 |
0011 | 3 | 3 | 3 | 3 |
0100 | 4 | 4 | 4 | 4 |
0101 | 5 | 5 | 5 | 5 |
0110 | 6 | 6 | 6 | 6 |
0111 | 7 | 7 | 7 | 7 |
1000 | 8 | -0 | -7 | -8 |
1001 | 9 | -1 | -6 | -7 |
1010 | 10 | -2 | -5 | -6 |
1011 | 11 | -3 | -4 | -5 |
1100 | 12 | -4 | -3 | -4 |
1101 | 13 | -5 | -2 | -3 |
1110 | 14 | -6 | -1 | -2 |
1111 | 15 | -7 | -0 | -1 |
如上图所述,补码的优势如下:
- 无符号和补码的优点在除非溢出,否则相同的硬件操作对于两种表示都是有效的。例如,1001加1会产生1010,在无符号中,1加9等于10;在补码中,给-7加一就产生-6。
所以计算机可以使用单个硬件电路来提供无符号或补码整数运算;运行在计算机上的软件可以为每个整数选择一个解释
。 - 补码相对反码和原码来说,同样的位数下,负数可以多一种解释。