计算机补码运算背后的数学原理是什么?

计算机补码运算背后的数学原理是什么?

想象一个时钟,指针指向的数字是计算机存储的数字。给这个数字做加法,就是把指针顺时针拨动;做减法,就是把指针逆时针拨:

当然,由于表盘大小是有限的(图中的大小是 8),如果拨得太远,指针可能会从两个方向超过 0,也就是发生上溢或者下溢。上溢时,你得到的数字是期望结果 - 8;下溢时,你得到的数字是期望结果 + 8.说简洁一点,就是所有的运算结果都会模 8.

时钟上只有 0 和大于 0 的数字,不能表示负数,这当然很不方便。所以我们保持 0 的位置不动,把 0 左边的一部分数字认为是负数。然后我们还是可以通过顺逆时针的拨动来实现加减法:

可以看到,这个时钟本身的工作方式不需要进行任何改变,就可以产生正确的结果。加法还是把指针顺时针拨动,减法还是把指针逆时针拨动。而我们使用原先的运算逻辑就可以对新的数字产生正确的运算结果,这说明现在的表盘刻度与原先的刻度具有等价性:也就是 -1 和 7 是等价的,-2 和 6 是等价的,以此类推。

这个现象在概念上叫同余:因为表盘上所有运算最终都是要模 8 的(不然会被截断),所以模 8 结果相同的数字在这个运算体系中是等价的。比如说 -1 与 7,模 8 都等于 7,所以两者在运算过程中可以相互替代。正因为如此,我们虽然把表盘上的数字采取了不一样的解释,但是由于新的解释与原先的数字是模 8 同余的,所以运算逻辑不需要进行改变。

现在,我们把表盘上的数字按照 0~7 写成二进制,再来看看:

——这就是补码。

那这么来定义表盘刻度有什么好处呢?或者说,使用补码来定义负数的二进制表示有什么好处呢?

我们可以发现,我们给表盘中加入负数之后,钟表的运算逻辑没有发生变化,唯一发生变化的是它的刻度。但是刻度这个东西是是给人来读的,时钟自己不知道自己现在是几。

也就是说,有符号数(也就是 -4~3)与无符号数(也就是 0~7)的运算是一样的,处理器不需要知道自己在处理有符号数还是无符号数,直接当做有符号数来处理即可。有符号数与无符号数之间的区别只是上层对数字的解释,也就是我们到底是把 111 解释为 7 还是 -1。