计算机为什么用补码表示负数

一般计算机中直接使用二进制表示数,其中的负数是如何表示的呢?

你会怎么表示

拿到这个问题,第一直观的反应是 用最高位表示符号位,后面的位表示数值?比如符号位 0 表示正数,1 表示负数。

以java中byte(8位)为例,即 +10 为:0000 1010。-10 为:1000 1010。

实际上计算机内部是用“补码”表示负数。

什么是补码

求一个2进制数的补码的方式:按位取反,加一。

例如 +10 的补码计算方式如下:

  1. 10 的二进制为 0000 1010。
  2. 按位取反:1111 0101。
  3. 然后+1:1111 0110。

所以 +10 的补码为 1111 0110。即计算机内部 -10 表示为 1111 0110。

使用补码的优势

给出结论:为了用同一种电路处理正数和负数的加法运算。

举例计算 10 + 2;

10的二进制为:0000 1010。2的二进制为:0000 0010,采用按位相加,满二进1位的思路计算:

0 0 0 0 1 0 1 0
+ 0 0 0 0 0 0 1 0
0 0 0 0 1 1 0 0

得到结果为 0000 1100,十进制为12。结果符合预期。

下面计算 10 + (-2)。

如果-2用直观的表达方式(最高位表示负数):1000 0010。

0 0 0 0 1 0 1 0
+ 1 0 0 0 0 0 1 0
1 0 0 0 1 1 0 0

计算得到 1000 1100,为 -12。显然不正确。

如果 -2 用补码的表达方式:1111 1110。

0 0 0 0 1 0 1 0
+ 1 0 0 0 0 0 1 0
1 0 0 0 0 1 0 0 0

忽略溢出的一位,结果为0000 1000,为8。用正数加法相同的策略:按位相加,满二进1位完成了负数的加法计算。

为什么补码这么“神奇”

因为 一个数的二进制补码 就是这个数在 二进制下的 负数表示。为什么这么说:

假设一个数十进制为A,二进制为 a (8位),则 a 的补码为:

  1. 按位取反:1111 1111 - a。(用全1减去 a 就是 a 的按位取反,这点显而易见)
  2. +1:1111 1111 - a +1。

溢出位忽略后,就为:0000 0000 - a。

可以看到 a 的补码,就是二进制下的 0 - a,就是 -a。

所以负数用补码表示后,就能通过加法完成 减法的运算。