Menu Close

什么是全加器?Carry-in 如何让二进制加法真正工作

在上一课中,我们介绍了 半加器(Half Adder)

什么是全加器?Carry-in 如何让二进制加法真正工作

半加器可以把两个二进制位相加。

它有两个输入:


并产生两个输出:


只需要两个逻辑门:


如果我们只需要计算两个二进制位,这已经足够了。

但真正的计算机几乎不会只处理一个二进制位。

CPU 通常需要处理:


甚至更大的数据。

一旦开始进行多位二进制加法,就会出现一个新的问题:

某一位的计算,可能需要接收前一位产生的进位。

而半加器没有这个输入。

为了解决这个问题,我们需要一个更完整的加法电路:

全加器(Full Adder)。

全加器可以把三个一位二进制输入相加,并产生两个输出:


1. 半加器的问题

先看一个简单的二进制加法:


从最右边开始:


因此这一位写下:


作为 Sum。

同时产生一个进位:


这个 1 必须送到左边下一位。

于是下一位的计算就不再只是:


而是:


最后这个 1,就是上一位传过来的进位。

问题就在这里。

半加器只有两个输入:


它没有地方接收这个额外的进位。

所以,半加器无法独立完成一般的多位二进制加法。

这正是 全加器 要解决的问题。

全加器增加了第三个输入,让前一位产生的进位可以参与当前这一位的计算。


2. 三个输入,两个输出

一个全加器有三个输入:


其中:


也就是进位输入

它产生两个输出:


也就是:


全加器计算的实际上是:


因为三个输入都只有一位,所以最大的情况是:


十进制的 3 用二进制表示就是:


所以两个输出位已经足够:


例如:


结果为:


也就是:


因此,全加器可以处理从:


到:


这 8 种输入组合,并产生一个最多两位的二进制结果。


3. 全加器真值表

全加器有三个二进制输入。

每个输入都可能是 01,所以总共有:


种组合。

完整真值表如下:

A B Cin Sum (S) Carry-out (Cout)
0 0 0 0 0
0 0 1 1 0
0 1 0 1 0
0 1 1 0 1
1 0 0 1 0
1 0 1 0 1
1 1 0 0 1
1 1 1 1 1

这张表已经完整描述了全加器的行为。

接下来,我们分别研究两个输出:


4. 找出 Sum

先只看 Sum:

A B Cin S
0 0 0 0
0 0 1 1
0 1 0 1
0 1 1 0
1 0 0 1
1 0 1 0
1 1 0 0
1 1 1 1

这里有一个非常明显的规律。

当三个输入中有奇数个 1 时:


例如:


这正好符合 XOR 的性质。

因此:


用布尔代数符号表示:


为了理解电路,我们可以把它分成两步。

第一步:


这里的 S1 表示第一个半加器产生的中间 Sum

第二步:


所以最终:


这已经给了我们一个非常重要的提示:

全加器可以用两个半加器连接起来实现。


5. 找出 Carry-out

现在只看 Carry-out:

A B Cin Cout
0 0 0 0
0 0 1 0
0 1 0 0
0 1 1 1
1 0 0 0
1 0 1 1
1 1 0 1
1 1 1 1

可以看到:

只要三个输入中至少有两个是 1,Cout 就会变成 1

例如:


所以:


同样:


也会产生进位。

而:


同样:


Carry-out 的一个常见布尔表达式是:


也可以写成更容易对应实际电路的形式:


如果使用前面定义的中间 Sum:


那么这个式子还可以写成:


这种写法能非常直观地帮助我们理解:

为什么两个半加器再加一个 OR 门,就可以组成一个全加器。


6. 用两个半加器构造全加器

这是本课最重要的概念之一。

我们并不需要从零开始设计全加器。

前面已经学过半加器,所以可以直接利用已有模块:


就可以组成一个完整的 Full Adder。

整个过程可以分为两个阶段。

第一个 Half Adder

第一个半加器负责计算:


它产生两个输出:


其中:


是第一个半加器产生的中间 Sum。

而:


是第一个半加器产生的 Carry。

概念上:


但是现在还没有结束。

因为我们还有第三个输入:


没有参与计算。


7. 第二个 Half Adder

第二个半加器接收两个输入:


其中:


于是第二个半加器计算:


并产生:


因此:


也就是:


这就是全加器最终的 Sum 输出

整个过程实际上非常容易理解:

第一个 Half Adder:


产生:


然后第二个 Half Adder 再计算:


于是第三个输入 Cin 就被加入了整个计算。


8. 为什么还需要 OR Gate?

现在我们已经有了两个可能的 Carry:


第一个半加器可能产生:


第二个半加器也可能产生:


而:


所以也可以写成:


无论是:


还是:


都意味着整个全加器必须产生:


因此,只需要用一个 OR Gate 把这两个 Carry 合并:


完整结构可以表示为:


因此,这种最直观的 Full Adder 实现一共使用:


也就是:

两个半加器 + 一个 OR 门。


9. 完整计算一个例子

假设:


我们要计算:


结果应该是:


下面看看电路是怎样一步一步算出来的。

第一个 Half Adder

首先计算:


也就是:


因此:


再计算 Carry:


所以:


第一个半加器得到:

第二个 Half Adder

接下来,把:


和:


相加。

也就是:


Sum 为:


因此:


第二个 Carry 为:


所以:


现在我们有:


最后经过 OR Gate:


所以:


得到:


最终结果:


也就是:


与:


完全一致。


10. Half Adder vs. Full Adder

现在,半加器和全加器之间的区别已经非常清楚了。

Half Adder

输入:


输出:


它计算:

Full Adder

输入:


输出:


它计算:


所以,两者最重要的区别,并不仅仅是 Full Adder 使用了更多逻辑门。

真正关键的区别是:

Full Adder 可以接收前一个二进制位产生的 Carry-in。

正因为有了:


我们才能把多个 Full Adder 一个接一个连接起来。

这也是全加器能够处理多位二进制运算的根本原因。


11. 从一个 Full Adder 到多位二进制加法

现在我们终于可以看到 Full Adder 真正重要的地方。

假设需要把两个 4-bit 二进制数相加:


我们可以为每一个 bit 使用一个 Full Adder。

也就是:


更完整地表示:


关键在于:

前一级 Full Adder 的 Carry-out,会成为下一级 Full Adder 的 Carry-in。

也就是:


这样,多个只会计算一位的 Full Adder,就可以共同完成一个完整的多位二进制加法。

一个非常小的逻辑模块,就这样开始扩展成真正接近 CPU 内部算术电路的结构。


12. 为什么 Full Adder 很重要?

Full Adder 看起来只是一个很小的数字电路。

但它解决了二进制运算中一个极其重要的问题:

如何把一个 bit 位置产生的信息传递给下一个 bit 位置。

一个 Full Adder 处理一个 bit。

多个 Full Adder 连接起来,就可以处理很多 bit。

整个发展过程可以表示为:


我们最开始学习的是:


这些非常简单的布尔逻辑操作。

然后,我们把它们组合成:


再加入 Carry-in,得到:


接着,把多个 Full Adder 连接起来,就可以得到:


也就是说:

计算机中的二进制算术,并不是一个神秘的软件过程。

它可以直接从最基础的逻辑门,一层一层构造出来。


Conclusion

**Full Adder(全加器)**是一种可以把三个一位二进制输入相加的数字电路。

它有三个输入:


和两个输出:


Sum 的逻辑表达式是:


Carry-out 可以写成:


一个最直观的 Full Adder 可以由:


构成。

第一个 Half Adder 计算:


并产生中间 Sum:


以及:


第二个 Half Adder 再计算:


得到最终的:


以及第二个 Carry:


最后 OR Gate 将:


合并成:


Full Adder 相比 Half Adder 最重要的升级,就是增加了:


正因为可以接收前一个 bit 位置产生的进位,一个 Full Adder 才能与下一个 Full Adder 连接。

于是:


就能够进一步扩展成:


的多位加法器。

那么接下来,一个自然的问题就是:

如果把多个 Full Adder 连在一起,Carry 一个接一个往前传,会发生什么?

这就引出了下一种非常重要的数字电路:

Ripple-Carry Adder(行波进位加法器)。

Posted in CPU结构