计算机反码和补码的意义


  初学二进制的人经常对反码和补码很疑惑,编程语言的书中也并不会过多解释此事,但是理解这个概念还是很有必要的。

综述

  反码和补码的概念主要是针对整数,也就是各种 int 而言的。运算的基础是逻辑电路,那么如何简化逻辑运算就是需要考虑的问题,由此使用了反码补码这两种运算。

  反码和补码的功能就是让计算机仅通过加法的逻辑电路就可以实现减法运算。

  反码的原意实际上是指 ones’ complement(对1求补),补码的原意是指 two’s complement(对2求补)。

  求补的意思是用该有限位数能表示的最大值减去该值。

  对于任何一个有限位的数来说,求补的结果都可以在该求补数的位数内表示。

  由于二进制中只有 0 和 1 两种状态,所以对一个二进制数对 1 求补实际上是按位取反。

  对 2 求补中的 2 实际上是代表着该有限位数的位能表示的状态数。

  比如 1 位的十进制数能表示 0 - 9 共 10 种状态,但状态数总是该位数能表示的最大数再加上 1,无法用该位数表示。

  用模减去该数就能得到补码。

  比如 10000000 - 1010010 = 0101110,事实上因为 10000000 = 1111111 + 1,稍加改变就成了 (1111111-1010010) + 1,所以求补码又可以表述为先求反再加 1。

无符号类型的二进制减法

例:10011001 - 10001100

思路:

10011001 - 10001100 ->

10011001 +(11111111 - 10001100) - 11111111 ->

10011001 +(11111111 - 10001100) + (1 - 100000000) ->

10011001 + 01110011 +(1 - 100000000) ->

10011001 + 01110011 + 1 - 100000000 ->

10011001 + 01110011 + 1

  1. 把减数按位取反得到反码:01110011
  2. 减去该有限位数能表示的最大值等于加 1 再减去模
  3. 将反码与被减数相加:01110011 + 10011001 = 00001100(舍去溢出位)
  4. 将结果加 1 得到 00001101
  5. 由于减去模实际上是在溢出位进行的,所以可以优化掉

注意,如果减数大于被减数,那么结果也遵循以上过程,但一般情况下无意义。

有符号类型的二进制减法

  对于有符号数的加减法运算,由于有符号数的最高位作为符号位,情况有会有所不同。

  在有符号情况下,正数在运算过程中反码和补码与原码一致,此时符号位按有效位进行运算

  负数的反码是符号位不变,有效位取反,补码是反码再加一。

  那么现在来计算一个有符号数的二进制减法:01001010 - 01100101

思路:

01001010 - 01100101 ->

01001010 + 11100101 ->

01001010 + 00011011

  1. 把减去正数变为加上负数
  2. 把负数取补码放回原式
  3. 把两数相加
  4. 若符号位为 0,此时即为结果,若符号位为 1,此时为负数的补码

参考:

3. 整数的加减运算

知乎-张天行