计算机中符号数常用的表示方法:
- 原码
- 反码
- 补码
这三种表示方法均有符号位和数值位两部分,符号位都是用 0 表示 “+”,用 1 表示 “-“。而数值位,三种表示方法各不相同。
1. 原码
原码是指一个二进制数左边加上符号位后所得到的码,即最高位为符号位。
当二进制数大于 0 时,符号位为 0
当二进制数小于 0 时,符号位为 1
当二进制数等于 +0 时,符号位为 0
当二进制数等于 -0 时,符号位为 1
例如,用 8 位二进制表示一个数:
1 | +10D = 00001010B |
一个 n 位的原码,可以表示 ${2}^n$ 个数(此时 +0 和 -0 分别为两个不同的数)。
数值范围是 $[-({2}^{n-1} - 1),{2}^{n-1} - 1]$。
2. 反码
反码表示法规定,正数的反码等于其原码,而负数的反码是对原码的数值位按位取反,并保留其符号位。
例如,对二进制原码 10001010 求反码:
1 | 10001010(原码) = 11110101(反码) |
在多数计算机中不采用反码表示数值。
3. 补码
在了解补码之前,先来看下,如果使用原码直接参与加减法运算会得到什么结果:
1 | 00000010 + 00000010 = 00000100,即 2 + 2 = 4,结果正确 |
可见原码的符号位不能直接参与运算,必须与其他位分开,这就增加了硬件的开销和复杂性。
3.1 补码的定义
正数和 0 的补码就是该数字本身,而负数的补码是对原码的数值位按位取反再加 1。
3.2 补码的运算
补码的符号位可以直接参与运算,例如:
1 | (0000) 0000 0010 (2D) |
1 | (0000) 0000 0010 (2D) |
1 | (0000) 0000 0010 (2D) |
3.3 补码的数值范围
在原码系统中,0 有两种表示方式(以 32 位的整数类型为例):
1 | 正零:0000 0000 0000 0000 0000 0000 0000 0000 |
按照负数补码的计算方法,对负零原码的数值位按位取反再加 1,可得:
1 | (0001) 0000 0000 0000 0000 0000 0000 0000 0000 |
由于溢出,可知正零和负零的补码是相同的,没必要区分正零和负零。
所以,在补码系统中,0只有一种表示方式。
因此,在32位的整数类型中,多出了一个数:
1 | 1000 0000 0000 0000 0000 0000 0000 0000 |
同时,在补码系统中,我们知道符号位可以直接参与运算:
1 | (0000) 1000 0000 0000 0000 0000 0000 0000 0001 (-2147483647D) |
于是,在补码系统中,$1$$\underbrace{ 00\cdots00 }_{n-1}$ 就表示了 n 位整数类型的最小值。
一个 n 位的补码,可以表示 $2^n$ 个数,其数值范围是 $[{-2}^{n-1},{2}^{n-1} - 1]$。
参考:
https://en.wikipedia.org/wiki/Signed_number_representations
https://zh.wikipedia.org/wiki/%E6%9C%89%E7%AC%A6%E8%99%9F%E6%95%B8%E8%99%95%E7%90%86