计算机不会算数,它只会开关。 加法是用几个开关(逻辑门)搭出来的电路:异或门算本位,与门算进位。 减法也不是单独的电路 —— 把减数取补码,减法就变成加法,一套电路干两件事。 [!tip] 承接前两篇 - [[01 二进制原理入门]]:0 和 1 是什么 - [[02 信息的数字化表示]]:真实世界怎么变成 0 和 1 - 本篇:这些 0 和 1 进去之后,电路怎么把它们算出来
1. 先搞懂一个前提:电脑没有"数字",只有"电压"
| 你以为电脑里的 | 实际在电路里的 |
|---|---|
数字 1 |
一根导线上的高电压(如 3.3V) |
数字 0 |
一根导线上的低电压(约 0V) |
| 加法 | 几个开关按规则互相控制 |
逻辑门(Logic Gate) 就是这样一个"看输入电压、决定输出电压"的小电路。
逻辑门没有智能。它只是一个物理器件: 输入端电压满足某个条件,输出端就给出对应电压。 所谓的"计算",就是电流在几百个门里按固定路线跑一遍的结果。
2. 四个基本逻辑门
| 门 | 口诀 | 真值表(A B → Y) |
|---|---|---|
| 与门 AND | 全 1 才出 1 | 0 0→0 0 1→0 1 1→1 |
| 或门 OR | 有 1 就出 1 | 0 0→0 0 1→1 1 1→1 |
| 非门 NOT | 反过来 | 0→1 1→0 |
| 异或门 XOR | 不一样才出 1 | 0 0→0 0 1→1 1 1→0 |
把它的真值表和我们小学的加法对比一下:
| 算式 | 本位结果 | 异或门输出 |
|---|---|---|
| 0 + 0 = 0 | 0 | 0 ✅ |
| 0 + 1 = 1 | 1 | 1 ✅ |
| 1 + 0 = 1 | 1 | 1 ✅ |
| 1 + 1 = 10 | 本位 0 | 0 ✅ |
完全一致。 异或门天生就是"加法本位"的电路。 [!note] 用一句话描述异或门 "两个输入不一样,输出 1;两个输入一样,输出 0。" 这个动作在数学上叫"模 2 加"(不进位加法)。
3. 半加器:两个门拼出"1 位加法"
现在解决进位问题。1 + 1 时本位是 0,但要多出一个 1 送给高一位。这个"多出来的 1"什么时候出现?
只有当 A 和 B 都是 1 的时候才出现 —— 这正是与门。
| 算式 | 本位(异或门) | 进位(与门) |
|---|---|---|
| 0 + 0 | 0 | 0 |
| 0 + 1 | 1 | 0 |
| 1 + 0 | 1 | 0 |
| 1 + 1 | 0 | 1 ✅ |
异或门 + 与门 = 半加器(Half Adder)
它只有两个输入 A、B。可是做 8 位加法时,每一位还要接收来自低位的进位。 半加器没有这个入口 —— 所以它只能当"半成品",名字也由此而来。
4. 全加器:真正能用的一位加法器
给半加器补上一个进位输入口,就是全加器(Full Adder),输入变成三个:A、B、Cin(低位进位)。
电路怎么搭
本位 S = A ⊕ B ⊕ Cin (两个异或门串联)
进位 Cout = A×B 或 (A⊕B)×Cin (两个与门 + 一个或门合并)
什么时候要往上进位?两种情况:
1. A 和 B 都是 1(A×B)
2. A、B 里有一个是 1,同时低位也送来了进位((A⊕B)×Cin)
任一种发生,就该进位 —— 所以最后用或门把两路合并。
完整真值表(8 种情况,只有 8 行)
| A | B | Cin | → | Cout | S | 含义 |
|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0+0+0 = 0 | |
| 0 | 0 | 1 | 0 | 1 | 0+0+1 = 1 | |
| 0 | 1 | 0 | 0 | 1 | 0+1+0 = 1 | |
| 0 | 1 | 1 | 1 | 0 | 0+1+1 = 2 | |
| 1 | 0 | 0 | 0 | 1 | 1+0+0 = 1 | |
| 1 | 0 | 1 | 1 | 0 | 1+0+1 = 2 | |
| 1 | 1 | 0 | 1 | 0 | 1+1+0 = 2 | |
| 1 | 1 | 1 | 1 | 1 | 1+1+1 = 3 |
A=0, B=1, Cin=1 → 0+1+1 = 2 → 二进制 10 → Cout=1, S=0 ✅
注意看:Cout 和 S 拼起来正好是两倍的 S 位的权。这说明电路算得没错。
5. 串起来算多位:行波进位加法器
一位不够用。要算 8 位、32 位,就把全加器并排串起来:
[FA bit7] ← [FA bit6] ← ... ← [FA bit1] ← [FA bit0]
↑ ↑ ↑ ↑
进/出 进/出 进/出 Cin = 0
- 最低位(bit0)的 Cin 固定接 0(没有更低的位了)
- 每一位的 Cout 接到左边高一位的 Cin
- 进位像波浪一样从右往左传 → 所以叫行波进位(Ripple Carry)
实例:算 5 + 3
0 0 0 0 0 1 0 1 ← 5
+ 0 0 0 0 0 0 1 1 ← 3
─────────────────
0 0 0 0 1 0 0 0 ← 8
↑
bit1 上 1+1 产生进位,传给 bit2
最高位的结果,必须等进位从最低位一路"爬"上来才知道。
32 位加法,最坏情况要等 32 个门依次翻转。
现代 CPU 用超前进位(Carry Look-ahead) 优化:直接由 A、B 一次性算出各级进位,不再排队等 —— 这就是现在一秒钟能算几十亿次加法的原因。
[!success] 乘法怎么办?
乘法就是加法的重复。 5 × 3 = 5 + 5 + 5。
CPU 用"移位 + 加法"实现:把乘数拆成 2 的幂次组合,每次左移一位(相当于 ×2)再决定加不加。
所以 CPU 里可以没有乘法器,但一定有加法器。
6. 减法:不用新电路,取个补码就行
这是整个设计里最漂亮的一招。
为什么要用补码?
如果给减法单独造一套电路,那 CPU 里就要有加法器 + 减法器 + …… 能不能让减法蹭加法器的车?
关键:如果能找到 −3 的一个二进制写法,让 7 + 它 的结果正好是 4,那就成了。
补码的求法:按位取反,再加 1
以 8 位、求 −3 为例:
3 = 0 0 0 0 0 0 1 1
按位取反 = 1 1 1 1 1 1 0 0
+1
───────────────────
−3 的补码 = 1 1 1 1 1 1 0 1
用加法器验证:7 + (−3)
0 0 0 0 0 1 1 1 (7)
+ 1 1 1 1 1 1 0 1 (−3 的补码)
───────────────────
1 0 0 0 0 0 1 0 0 ← 多出第 9 位
把最高位溢出的 1 直接丢弃 → 剩下 00000100 = 4 ✅
因为 8 位电路"装不下"第 9 位,溢出部分自动消失。
这是补码设计的精妙之处:溢出的丢弃不是错误,而是设计好的机制。
换句话说,"减 3"和"加 245"(11111101 的十进制值)在 8 位电路里是同一件事。
减法秒变加法的操作
| 要算 | 实际让加法器算 |
|---|---|
A − B |
A + (−B 的补码) |
所以一个 8 位加法器,只要在 B 的输入端加一排非门(把 B 取反)再让 Cin = 1(完成"+1"),同一套电路立刻能算减法。
一半的数分给负数(最高位当符号位),所以正数只剩 0~127。
7. 一图总结:从电压到加法
电压高低 → 逻辑门(0/1 的规则) → 一位全加器 → 多位加法器 → 减法/乘法
高=1 低=0 与门·或门·非门·异或门 异或算本位 串联 + 进位 补码 / 移位
与门算进位
| 层级 | 做什么 | 关键点 |
|---|---|---|
| 电压 | 表示 0 和 1 | 只有两档,抗干扰 |
| 逻辑门 | 0/1 的运算规则 | 无智能,纯物理开关 |
| 全加器 | 一位加法 | 异或管本位,与门管进位 |
| 多位加法器 | 多位加法 | 进位逐级传递(行波) |
| 加减乘 | 全都归到加法 | 补码 + 移位 |
计算机的"计算能力",本质上是从"开关"里长出来的。 没有魔法,只有一层层搭起来的规则。
8. 常见误区自查
- "CPU 会算数" —— CPU 不会,它只会让电流穿过一堆门电路。
- "减法需要单独的电路" —— 不需要,取补码后走加法器,溢出丢弃即可。
- "溢出丢弃是 bug" —— 是设计。正因为丢弃,
A + (−B 补码)才能等于A − B。 - "乘法是专门的乘法电路" —— 本质是移位 + 重复相加。
- "半加器和全加器只是名字不同" —— 差一个进位入口,全加器才能串联成多位。
- "进位是瞬间传完的" —— 行波进位要排队传,这是老式加法器的主要瓶颈。
9. 自测题(先自己算,再点开答案)
因为本位由异或门决定,而"两个输入一样时异或门输出 0"。
1+1=10,本位上确实应该写 0,那个 1 交给进位。
[!question]- Q2. 进位 Cout 什么时候是 1?
两种情况:A 和 B 都是 1;或者 A、B 中有一个是 1 且低位送来了进位。
对应公式 Cout = A×B 或 (A⊕B)×Cin。
[!question]- Q3. 用 8 位补码算 10 − 4,写出过程。
−4 的补码:00000100 → 取反 11111011 → 加 1 → 11111100
10 = 00001010
00001010 + 11111100 = 1 00000110
丢弃溢出的最高位 → 00000110 = 6 ✅
[!question]- Q4. 8 位有符号整数能表示的范围是多少?为什么?
−128 ~ 127。
最高位拿来当符号位,剩下 7 位表示大小;正数占 0~127,负数占 −128~−1。
[!question]- Q5. 为什么 CPU 里不需要"减法器"?
因为 A − B 可以改写成 A + (−B 的补码),
用同一个加法器配合"取反 + Cin=1"就能完成,省掉一整套电路。
10. 下一步学什么
- [x] 实现"电路计算"之路 → 已写成 04 实现电路计算之路(布尔 → 香农 → 晶体管 → 芯片,门是用什么造的)
- [ ] CPU 是怎么工作的 —— 运算器、控制器、寄存器、时钟(五大部件)
- [ ] 时钟与频率 —— 为什么 CPU 要"滴答"着走,3GHz 是什么意思
- [ ] 内存与存储 —— 这些算出来的数存在哪,为什么关机就没了
- [ ] 逻辑运算的实际用途 —— 掩码、权限位、位图(
chmod 755为什么是 7) - [ ] 浮点数 —— 小数怎么算,为什么
0.1 + 0.2 ≠ 0.3
相关笔记
- 04 实现电路计算之路 → 下一篇:这些门是用什么器件造的、这条路谁铺通的
- 02 信息的数字化表示 ← 上一篇:真实世界怎么变成 0 和 1
- 01 二进制原理入门 ← 第 01 篇:二进制基础
- 📇 计算机基础 · 索引
- 🏠 返回主页