编程加

为什么计算机要使用二进制?

2021年3月11日

二进制(binary感到陌生是正常的,因为日常生活中很少有使用二进制的场景。人类最常用的计数系统莫过于十进制了,这可能是因为人有十根手指的缘故,使用十进制计数比较符合直觉。

但我们也不是没接触过其他计数系统。表示月份用十二进制,“半斤八两”用十六进制,表示时间用二十四进制和六十进制。

在数学里,表示 n 进制数一般会引入 n 种不同的符号。十进制通常使用 0–9 表示。身份证号的最后一位在 0–9 的基础上引入了 X(即罗马数字中的十),这其实也是一种十一进制的表示方法。

类似地,十六进制通常在 0–9 的基础上,引入字母 A–F。从零开始计数像是这样子:0, 1, 2, …, 9, A, B, C, D, E, F, 10, 11, 12, …其中 A 对应十进制中的 10,B 对应十进制中的 11,F 对应十进制中的 15,10 对应十进制中的 16,以此类推。

10(读作“一零”而不是“十”)在不同进制中表示的数不同。确切地说,在 n 进制中,10 表示 n。所以在可能产生歧义的时候,应当说明使用的进制。

图片来源:a daily comic by Sanjay Kulkarni

上图的外星人只有四根手指,它们很自然地使用四进制。在它们的文明里,10 = 四,并没有 4 这个符号。这也是为什么外星人看起来一脸疑惑──就跟你第一次看见身份证号中的 X 一样。

二进制通常使用 0 和 1 表示,像是 1101000。我们把二进制数的每一位称为一个比特(bit──一个由 binary 和 digit 混合而成的单词。

计算机使用二进制,主要是因为电路实现起来简单。这跟人类倾向于使用十进制别无二致──试想如果我们在日常生活中使用二十进制甚至六十进制计数,那得多费脑子和脚趾,这恐怕只有法国人才可以做到

电路并不理解数字,所有的含义都是人为赋予的。二进制的每一位有两种可能性,因此我们只要在电路中找到两种状态,分别赋予 0 和 1 的含义,就可以表示一个比特了。我们可以设定一个电压阈值,将电压划分为低电平和高电平两种状态──比如,在一个 5V 供电的电路中,认为 0–2.5V 是低电平,2.5V–5V 是高电平──然后,把低电平赋予 0 的含义,把高电平赋予 1 的含义,这样,我们便可以通过高低电平表示一个比特。

找到表示一个比特的方法之后,就可以考虑怎样实现计算了。不妨先来复习一下初中物理,下图是一个由电源、开关 S1 和 S2 和灯 L 组成的电路。

显然,只有开关 S1 和 S2 同时闭合的情况下,才能形成回路,灯 L 亮。如果把开关的断开和闭合、灯的灭与亮分别赋予 0 和 1 的含义,那么当且仅当 S1 和 S2 都是 1 的时候,L 为 1。将 S1 和 S2 看作输入、L 看作输出,列举所有可能性,可得到下表:

输入输出
S1S2L
000
010
100
111

这就是布尔代数中的与(AND运算。

在实际的数字电路中,晶体管充当了上图中开关的角色,电压的大小可以控制“开关”的打开与闭合,而这些“开关”组成了一个个逻辑门(logic gate,包括上面的与门(AND gate。常用的逻辑门还有很多,比如非门(NOT gate或门(OR gate等。有了这些基础的逻辑门,我们就可以利用布尔代数,将它们组合成任意输入到任意输出的逻辑门,从而实现更复杂的运算。

一个典型的案例是加法器(adder,用于计算两数之和。

计算机做加法和人类做加法的方法差不多,也是依次计算两个加数的每一位并处理好进位(carry,我们小学一年级就已经学会了。

如果不考虑沟通成本,要计算 n 位数的加法,完全可以找 n 个人站成一排,告诉每个人需要计算的两个数字是多少、上一步(低位)产生的进位是多少,他们就可以分别算出这一位的和和产生的进位。

上图是 4 个人做 4 位十进制加法的例子,蓝色部分可以看作是三个输入,橙色部分可以看作是两个输出。小人只要能够根据输入计算输出,就可以组成一个 4 位加法器。我们要做的就是设计两个逻辑门,根据蓝色部分的输入,分别输出两个橙色部分的值。

十进制数的排列组合非常多。但如果是两个二进制数,我们可以轻易列举出所有可能性:

输入输出
加数 A加数 B进位
0000
0101
1001
1110

简单起见,我没有在输入中加入低位产生的进位,否则可能性会多一倍。这种加法器的“半成品”也有名字,称为半加器(half adder

对比可以发现,计算输出中的进位可以使用上面的与门实现。和可以用另一种名叫异或门(XOR gate 的逻辑门实现。

或门很好理解,输入只要有 1 就输出 1。异或的全称是 eXclusive OR,是一种排斥或,与或的区别在于需要排除两个输入相同的情况。从效果上来看,异或可以看作是加法运算(因此也常被写为⊕)。

理论上,将 n 个 1 位加法器串起来就可以组成一个 n 位加法器。实践中,加法器规模通常成倍扩大:两个 1 位加法器可以组成一个 2 位加法器,有了 2 位加法器后,将两个 2 位加法器组成一个 4 位加法器,以此类推……实际计算机中的加法器也更复杂,比如使用超前进位的技术,减少等待低位进位的时间。

回过头来看,计算机一定要使用二进制吗?

显然不是。只要在电路中找到表示三种状态的方法,并且将布尔代数扩展到三元,就可以造出三进制计算机。

历史上也确实有过三进制计算机的尝试,但是就目前而言,二进制计算机赢了。

编程加公众号