导言

这一篇小短文需要前面这一篇知识的的理解。二进制与布尔代数

我们知道计算机的大脑是中央处理器CPU,而CPU由运算逻辑部件ALU(Arithmetic and Logic Unit)、寄存器部件和控制部件组成。今天我们要说的ALU是CPU的数学大脑,是负责数值运算的部件。ALU有两个单元,一个是算术单元,一个是逻辑单元。


算术单元

算术单元主要是对数值进行运算。

首先是加法

首先我们来做一个简单的1 bit数据的加法,也就是两个一位二进制的加法。情况是这样

0 0 = 0

0 1 = 1

1 0 = 1

1 1 = 0但是要进一个1,这是因为1 1=2,但是二进制里没有2这个数的表示,因此需要进位,十进制的数2转换为二进制数就是10。

如果把0和1分别代表真和假,你会发现刚好布尔代数里的XOR操作刚好满足可以对应着这四种基本运算,但是1 1需要进位比较麻烦,因此我们可以加一个与门进行AND操作,如下图:

怎么把cpu个数给改回来(让小朋友懂一点计算机)(1)

半加器的内部结构

CARRY输出进位标志

而SUM则输出除了进位之外的和

这样,两二进制数相加就会得到两个标记,而这两个标记的组合则可以表示所有可能的情况,虽然只是两个1 bit数据相加的情况。现在,我们把这种电路结构固定下来,并且形成新的一个电子元器件,称之为半加器。

怎么把cpu个数给改回来(让小朋友懂一点计算机)(2)

半加器

但是这还是有一点点问题,的确,两个1 bit的数据相加,用半加器的确没啥问题,但是如果是多个bit的数据相加呢?半加器好像不行。就像下图中的红框中的情景,除了两个数自身的相加外,还得把进位的 1 也要加上,这就是三个数相加的问题。

怎么把cpu个数给改回来(让小朋友懂一点计算机)(3)

3比特的数据相加

为了解决这个问题,全加器出来了,全加器是两个半加器加一个或门组成。它的输入有三个值,分别为数A,数B,还有进位C,它的输出有两个值,分别为 进位。如下图:

怎么把cpu个数给改回来(让小朋友懂一点计算机)(4)

全加器的内部结构

因此,加法器里最关键的两个部件我们有了,那么现在我们可以制作一个8位加法器,8位加法器由1个半加器和 7个全加器组成。如下图:

怎么把cpu个数给改回来(让小朋友懂一点计算机)(5)

8位加法器

首先数A的第一位A0与数B的第一位B0使用半加器相加(PS.程序员的世界里一般第一个数的下标为0,这一点很常见),然后输出相加的 还有 进位标志,然后A1与B1 还有进位标志 相加,然后输出和和进位标志。一直这样下去,直到A7与B7相加,但是注意哦,如果A7 与 B7相加产生了进位,那就产生了 溢出,溢出就是数值存放所需要的位数已经超过了用来表示的位数。这就像一个100毫升的杯子,你倒入了50毫升的牛奶之后,又倒入了70毫升,那么,牛奶就会从杯子里溢出了。因此,要表示越大越复杂的数,我们需要更多的位数。

减法

在这里,我需要把减法单独拎出来讲一下。因为减去一个数等于加上这个数的负数,例如 10-8 = 10 (-8),这样就把所有的加减运算都转化为了加法运算,前面我们说到过,二进制中的第一位如果是1 的话则表示这个数是负数,如果是0的话,则表示这个数是正数,那么如何在计算机内部做到正负数之间的加减呢?

当然,我们已经解决了这个问题。我们是通过特殊的存储方式来解决的。

机器数

首先我们需要了解一下机器数和原码反码补码。

一个数在计算机中的二进制表示形式, 叫做这个数的机器数。机器数是带符号的,在计算机用一个数的最高位存放符号, 正数为0, 负数为1。数字一般以补码的形式存放在计算机中。

比如,十进制中的数 3 ,计算机字长为8位,转换成二进制就是00000011。如果是 -3 ,就是 10000011 。因为第一位是符号位,所以机器数的形式值就不等于真正的数值。例如上面的有符号数 10000011,其最高位1代表负,其真正数值是 -3 而不是形式值131(10000011转换成十进制等于131)。所以,为区别起见,将带符号位的机器数对应的真正数值称为机器数的真值

原码, 反码和补码的概念.

原码就是符号位加上真值的绝对值, 即用第一位表示符号, 其余位表示值. 比如如果是8位二进制:

[ 1]原码= 0000 0001

[-1]原码= 1000 0001

反码

反码的表示方法是:正数的反码是其本身,负数的反码是在其原码的基础上, 符号位不变,其余各个位取反。

补码

补码的表示方法是:正数的补码就是其本身,负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后 1. (即在反码的基础上 1)。实际中,计算机内部是存储补码的(至于怎么存储的,后面会讲到)。

[ 10]补码 = 00001010

[- 8 ]补码 = 11111000

相加得:

怎么把cpu个数给改回来(让小朋友懂一点计算机)(6)

两个8比特数相加

10 (-8) = 2

[ 2 ]补码 = 00000010 = 十进制的2

你会发现多出了一位,这一位是进位得到的,它会被直接丢弃掉,然后就直接得到二进制数00000010,就是十进制的2。这一结果的出现并不是巧合,这是人为设计的结果。

补码的出现使符号成为了运算的一部分,这种设计使计算机内的运算只需要加法,而没有减法。

更多细节详见链接http://www.cnblogs.com/zhangziqiu/archive/2011/03/30/ComputerCode.html

乘法与除法

讲完了加减法,那么乘除法又是怎么运算的呢?乘法电路和加法电路没什么本质区别,只是有更多的加法器。

除法

先直接来个例子,12/5 = 2.4,这一点我们都知道,当然,我们小学好像学过12/5 = 2 余2 ,这也对,为什么是这样呢,因为

12 - 5 = 7 | 7- 5 = 2 | 2好像减不了5,因为2比5小,好了,那么我们现在就知道 12/5 = 2 余 2 ,如果你只算需要整型数据,那么这就够了,Int a = 12/5 那么a = 2,但是如果你需要浮点数,那么就可以将余下的2乘以10然后再不断的减去5,你就可以得到浮点数float b = 12/5 那么a的值就是2.4。

乘法

还是直接举例子 12* 5 = 60,你可以看做 12 12 12 12 12 = 60 ,也就是5个12相加,当然也可以看做12个5相加,这很笨,但是很管用,他一般运用在很简单的ALU上,例如玩具,普通家电中。

在高端的计算机中,有专门的部件来进行相关的乘除法运算,但其根本,还是由很多的逻辑门构成。


逻辑部分

除了算术运算,ALU还需要做一下不是很侧重于运算的工作,比如,判断一个数是不是0(因为两个数如果相等的话,相减就是0,所以这个可以判断两个数是否相等),是不是偶数,是否溢出,这些都是ALU逻辑单元所需要做的事情。

下图为ALU判断一个数是否为0 的电路结构。

怎么把cpu个数给改回来(让小朋友懂一点计算机)(7)

这里是判断一个8比特数是否为0的电路结构

一般我们使用这个符号将ALU抽象出来,这个有点像大写的V。

怎么把cpu个数给改回来(让小朋友懂一点计算机)(8)

ALU标识

总结

其实无论多么高深复杂的功能,都是由一个个简单的晶体管拼接而成,电路这种特殊的结构使得它天生适合于二进制。二进制天然不是电路,电路天然是二进制。

资料来源

特此鸣谢 The Crash Course

讲述原码补码反码的网页链接 http://www.cnblogs.com/zhangziqiu/archive/2011/03/30/ComputerCode.html

本篇有许多的图片来源于网络,如有侵权,立即删除。


,