补码之美

horst_hu 发布于 2014/01/22 11:06
阅读 828
收藏 16

screen shot 2014-01-16 at 9 59 26 pm

在计算机中,为什么 -1 要用补码表示为 1111 ?

首先要了解 CPU 的基本单元 ALU 模块。在 ALU 里,加法是最基本的运算。通过程序,乘法可以转换为加分,除法可以转换为减法。补码表示,则可以让减法直接转换为加法。这样,ALU 核心只需要加法器就好,加法器可以通过集成电路中的晶体管来实现。

要将减法转换为加法,在数学公式里,只要加一个括号即可:

X - Y = X + (-Y)

在 CPU 里,如果想让加法器具备减法功能,核心是负数如何表示。

原码

大自然赐予了我们硅,硅是很稳定的半导体,通过 PN 结等精细工艺,可以做成各种晶体管。在晶体管的世界里,基本状态只有 on 和 off 两种,也就是只有 
1 和 0。于是,在计算机里,我们采用二进制来表示整数。

这样,最自然的想法是,对于正整数来说,直接从十进制转换成二进制就好。比如 1 用 0001 来表示,2 用 0010 来表示。

负整数怎么来表示呢?增加一个符号位来表示?比如二进制的最高位为 0 时表示正数,为 1 时则表示负数。

这样,-1 用 1001 表示,-2 用 1010 表示。这就是原码的概念。

在原码的表示里:

1 - 1 = 1 + (-1) = 0001 + 1001 = 1010 = -2

显然,原码表示法,不能把减法变成加法,悲催。

补码

据说,所有科学问题,最后都是数学问题,而所有数学问题,最后都离不开哲学。

哲学太深奥了,我们来看看从数学上,如何把 X + (-Y) 转换成二进制相加。

我们希望有某种表示方法,使得 1 + (-1) = 0000 现在 1 用 0001 来表示,-1 应该怎么表示?

-1 = 0000 - 0001
    = 10000 - 0001  (高位借一)
    = (1111 + 0001) - 0001
    = (1111 - 0001) + 0001(第一步:取反)
    = 1110 + 0001(第二步:加一)
    = 1111

也就是说,如果 -1 用 1111 来表示,则 1 + (-1) 的二进制表示通过加法就能进行减法操作,达成了我们最初的目的。

进一步,针对所有负整数:

-Y = 0000 - Y
     = (1111 + 1 ) - Y
     = (1111 - Y) + 1   将正整数 Y 的二进制先取反、再加一

整数转换成二进制后,先取反,再加一,这就是负整数的补码表示。正整数的补码跟原码一样。

到此为止,补码的前世今生就说完了,但还有些有意思的事情。

简单之美

可以说,补码的出现,是为了能让 ALU 在设计时更简单:只需要加法电路就好,不需要减法电路。追求简单,极致的简单,这能给性能、工业化等带来很大价值。

再从数学上来看,整数遵循一些很容易被我们忽略的重要规律:

  1. 数轴上,左边的数永远小于右边的数。比如 -8 < -2 < 0 < 3 < 5
  2. 数轴上,只有一个零。
  3. 相邻整数之间相差一。

来看补码表示:

-8      -7         -6        -5        -4        -3       -2      -1       0          1         2        3         4        5         6         7
1000 | 1001 |  1010 | 1011 | 1100 | 1101 | 1110 | 1111 | 0000 | 0001 | 0010 | 0011 | 0100 | 0101 | 0110 | 0111
  1. 只看负数的补码表示,明显 1000 < 1001,补码表示下,左边的负数很自然小于右边的负数。
  2. 很明显只有一个零,就是 0000,不存在 -0 跟 0 的表示不一样。
  3. 再看相邻整数之间,左边的整数加一,就是右边的整数,包括 1111 + 1 = 0000 。

初看补码,有些怪异、不直观,但在二进制的世界里,补码是如此自然。第一个想出用补码来表示整数的人,真是个天才啊。

(完)

原文链接:https://github.com/lifesinger/lifesinger.github.com/issues/187

之前学组成原理的时候,为了应付考试只知道补码原码之间的转换加减。不怎么懂,今天再看看感觉有点意思,哈哈

加载中
0
雨翔河
雨翔河

我一开始学c的时候就是在学进制转换,后来自己画了一个表格来实现转换,现在看来发现更有意思。

0
gzwxn
gzwxn
补码似乎用最高位为负权来定义更好。文中那种“负数绝对值全部取反再加一”只是一种技巧。
0
翟志军
翟志军

我不是很明白那个:

= 10000 - 0001  (高位借一)



horst_hu
horst_hu
回复 @翟志军 : 那就验证那句话了,所有数学问题,最后都离不开哲学,所以有时候你不需要明白
翟志军
翟志军
回复 @horst_hu : 抱歉, 我想像不出,0000高位还有一位。
horst_hu
horst_hu
@翟志军 你要想想它前面还有一位就想了,没有超过计算机的寻址空间就行了
翟志军
翟志军
回复 @horst_hu : 能否解释下,什么叫高位借一。。。而且,0000哪来的高位?
horst_hu
horst_hu
总有一天你会明白的
0
zzy_zzy
zzy_zzy

引用来自“gzwxn”的答案

补码似乎用最高位为负权来定义更好。文中那种“负数绝对值全部取反再加一”只是一种技巧。
赞同
0
崔钢
崔钢
这有啥意思?不太明白,有啥美的?
horst_hu
horst_hu
美不美自己知道,自己感觉美就行了,哈哈
返回顶部
顶部