编程加

0 和 1 可以表示任何东西……吗?

2021年3月12日

计算机只认识 0 和 1,到底是怎么存储文字、图像,甚至是视频的?难道只用 0 和 1 就可以表示任何东西吗?

如何将一个东西用 0 和 1 表示,本质上是如何将这个东西数字化。

考虑一个问题,如果你只能使用数字来表示单词,你会怎么做?

一个很自然的想法是,将所有字母编号,构造出一张数字 ⇄ 字母的「互译表」:

数字字母数字字母数字字母
0a9j18s
1b10k19t
2c11l20u
3d12m21v
4e13n22w
5f14o23x
6g15p24y
7h16q25z
8i17r

然后就可以使用 0–25 来写单词了!比如 apple 就是 0 15 15 11 4

但是,内存的空间是连续的。如果我们把中间的空格删除,就会产生歧义:01515114 可以被理解成 0 15 15 11 4(apple),也可以被理解成 0 1 5 1 5 1 1 4(abfbfbbe)。

最简单的解决方法就是用固定长度的数字表示每个字母。比如,表中最大的数字 25 是两位数,我们加前导零把所有数字都变成两位数,apple 就变成了 00 15 15 11 04。即便去掉中间的空格,也不会产生歧义。

用二进制编码跟十进制编码没有本质区别,前者是 0 和 1 的排列组合,后者是 0–9 的排列组合。

下表是目前计算机上普遍使用的 ASCII 编码,充分利用所有 7 位的二进制数 000 0000 ~ 111 1111 编码了 128 种字符。表格的第 1 行是数字的前 3 位,前 4 列是数字的后 4 位。

比如 110 1000 对应小写字母 h。
《欢迎来到二进制的世界!》的头图
如果试着翻译一下第一篇文章在公众号上的头图,会得到 helloworld。
盲文的 26 个英文字母

计算机之外也有编码系统的存在,比如盲文也是一种编码系统,但是盲文没有像 ASCII 编码一样充分利用 6 个点的所有组合。可以观察到,所有字母要不就是左上角有点,要不就是跟左上角相邻的都有点。这是为了让盲人更好地定位。

所以,不同场景设计出的编码系统可能是完全不一样的。ASCII 为了节约昂贵的内存,充分利用了数字的所有排列组合。盲文使用了更多的点,但是增加了阅读体验。

在某些场景,顺序也很重要。用 0 和 1 表示(有限的)自然数也是一种编码,我们可以把所有需要表示的自然数列出来,与二进制数任意地一一配对,比如用 3 位二进制数 000 ~ 111 编码自然数 0, 1, 2, 3, 4, 5, 6 的时候,偏是把 010 对应自然数 0,但是这种乱序的编码方式在做运算的时候就头疼了。

《为什么计算机要使用二进制?》 中提到的加法器可以做 n 位二进制数加法,只要我们按照计数的顺序安排这些自然数,加法器就可以对这种编码下的数字做正确的加法运算。

二进制表示的数字
0000
0011
0102
0113
1004
1015
1116
比如,001(1) + 010(2) = 011(3)

当把自然数扩展到整数的时候,我们把一半的位置留给负数。为了让负数加法能够复用上面的加法器电路,人们特别地安排了负数的排列。

二进制表示的数字
0000
0011
0102
0113
100-4
101-3
110-2
111-1

可以发现,负数的顺序有点奇怪,但是每个数字跟它的相反数的二进制编码之和都是 000 或者 1 000(在一个 3 位加法器看来,这也是 000)。比如,001(1) + 111(-1) = 1 000(0)。这种编码负数的方式,就是教科书上所说的补码,可以让加法器不需要考虑正负性,算就完了。

上面都是编码有限个符号的例子。现实世界是连续的,那些不可枚举的物理量怎么用 0 和 1 表示呢?

我们无法用有限个 0 和 1 表示无限的可能性,但是我们可以通过采样,将现实世界中的物理量变成离散的值。这就好比我们用尺子去测量一个物体,总是会估读到毫米,这无疑是不精确的,但是我们能够接受这种误差。

在计算机中也是这样表示颜色的。我们常见的 RGB 颜色模型将颜色分为红(Red)、绿(Green)、蓝(Blue) 3 个分量,分别描述这个颜色有多红、多绿和多蓝。每个分量有 256 种取值(二进制数 0000 0000 ~ 1111 1111),3 个分量放在一起就可以表示颜色。

比如,红色可以表示为 11111111 00000000 00000000,换算成十六进制就是 FF0000(你可能在很多软件中都见过这种表示方式)。在 RGB 颜色模型里,一个颜色从最「不红」到最「红」只有 256 个级别,但这对屏幕显示来说已经足够了。

当然,有很多目前还很难采样的东西,比如气味;又或者是,有时我们无法接受采样带来的误差,比如 π 的精确值……这些就没有办法用有限个 0 和 1 表示了。

编程加公众号