🧮 第8章 算法和计算机
📄 一句话概括

二进制、八进制、十六进制指的是同一批数,只是写法不同。 电脑只认二进制,因为一根线只有两种状态——有电、没电。 十六进制是二进制的压缩写法:每四位二进制正好对应一位十六进制。

📝 本章和前面几章的关系

前七章讲「怎么想」,这一章往下钻一层:电脑用什么表示数。 这是全书唯一一章不涉及算法、只涉及表示的章节,但它是前面所有算法的地基。 这一篇先把三种进制的写法认清楚,下一篇讲怎么互转。

一、同一个数,四种写法

十进制 173、二进制 0b10101101、八进制 0o255、十六进制 0xad——这四个指的是同一个数。 就像「173」「一百七十三」「CLXXIII」是同一个数一样:写法不同,数没变。 进制只是「逢几进一」的规矩。十进制逢十进一,二进制逢二进一,十六进制逢十六进一。

进制 写法 用了几种数字 位数
十进制 173 0~9 共 10 种 3
二进制 0b10101101 0 和 1 两种 8
八进制 0o255 0~7 共 8 种 3
十六进制 0xad 0~9 加 A~F 共 16 种 3

注意位数那一列:同一个数,二进制要 8 位,其他三种都是 3 位。这就是二进制「不好读」的具体表现。 Python 里那三个前缀(0b、0o、0x)就是用来区分写法的——不加前缀, 10101101 会被当成十进制的一亿多。

二、为什么电脑只认二进制

演示里那句话最直白:一根线只有两种状态——有电、没电。 两个状态正好对上 0 和 1。 要是想用十进制,一根线得能分出十档电压,档位一多,干扰一起来就分不清了。 这跟机械时代的算盘不一样:算盘的珠子位置是「看得见摸得着」的,分十档没问题。 电子元件靠电压判断,电压本身是有噪声的——档位越少越可靠。

所以硬件层面只有 0 和 1。八进制、十六进制都是给人看的,电脑内部还是那一串 0 和 1。 这条区分很重要:进制不是电脑的需要,是人的需要。人受不了看八个 0 和 1, 才发明了十六进制这种缩写。

三、十六进制为什么好读

173 的二进制是 10101101,八位,一眼数不清。 把它四位一组切开:1010 和 1101。1010 是十进制 10,写作 A;1101 是 13,写作 D。 合起来就是 AD。 两位数就写完了。这就是十六进制在编程里到处都是的原因——它是二进制的压缩写法。

二进制四位 十进制 十六进制
0000 0 0
1001 9 9
1010 10 A
1101 13 D
1111 15 F

为什么正好是四位对一位?因为 2 的 4 次方是 16。这也是十六进制存在的原因——16 是 2 的整数次幂。 所以转换时不用算,照着表抄就行。这一条让十六进制成了「人机之间最省事的桥」。

四、最常见的一处:颜色

#A3F2C1 这样的颜色值,拆开是三组两位十六进制:A3、F2、C1。 分别是红 163、绿 242、蓝 193。每组两位十六进制,范围正好 0 到 255,也就是 8 位二进制。 三个 255 是纯白 #FFFFFF,三个 0 是纯黑 #000000。

这一条能解释很多日常现象:为什么颜色值总是 6 位(三组各两位), 为什么「16 位色」「24 位色」这么叫(每个像素占多少位)。 所以看到 # 开头的六位色值,就可以理解了:它不过是「三个 8 位二进制数」的缩写, 而每一位都能在 0 到 255 之间取值,因为 8 位二进制最大就是 255。

五、动手 Demo:一个数,四种写法,顺便拆一个颜色值

用 Python 的三种前缀把 173 分别写成二进制、八进制、十六进制。 再把一个颜色值拆成三组,看每组的十进制是多少。

n = 173
print(n)
print(bin(n))
print(oct(n))
print(hex(n))
print(bin(n)[2:])

print(0b10101101, 0o255, 0xad)

c = 'A3F2C1'
print([int(c[i:i + 2], 16) for i in range(0, 6, 2)])
print(int('FF', 16), int('FF', 16) * 3)

实跑输出:

--------------------------------------------------------------------
二进制、八进制与十六进制
--------------------------------------------------------------------


  ① 同一个数,四种写法
  --------------------------------------------------------------------

| 进制 | 写法 | 用了几种数字 | 位数 |
|---|---|---|---:|
| 十进制 | 173 | 0~9 共 10 种 | 3 |
| 二进制 | 0b10101101 | 0 和 1 两种 | 8 |
| 八进制 | 0o255 | 0~7 共 8 种 | 3 |
| 十六进制 | 0xad | 0~9 加 A~F 共 16 种 | 3 |

  这四个指的是同一个数。就像「173」「一百七十三」「CLXXIII」是同一个数一样——写法不同,数没变。

  ② 为什么电脑只认二进制
  --------------------------------------------------------------------
  一根线只有两种状态:有电、没电。
  两个状态正好对上 0 和 1,多一个状态就得靠「电压分几档」
  来分辨——档位一多,干扰一起就分不清了。
  所以硬件层面只有 0 和 1。八进制、十六进制是给人看的,电脑内部还是那一串 0 和 1。

  ③ 十六进制为什么好读
  --------------------------------------------------------------------
  十进制 173 的二进制是 10101101,八位,一眼数不清。
  把它四位一组切开:1010 1101
  1010 是十进制的 10,写作 A;1101 是 13,写作 D
  合起来就是 AD ——两位就写完了。

| 二进制四位 | 十进制 | 十六进制 |
|---|---|---|
| 0000 | 0 | 0 |
| 1001 | 9 | 9 |
| 1010 | 10 | A |
| 1101 | 13 | D |
| 1111 | 15 | F |

  每四位二进制正好对应一位十六进制,所以转换时不用算,直接照着表抄。
  这就是十六进制在编程里到处都是的原因——它是二进制的「压缩写法」。

  ④ 最常见的一处:颜色
  --------------------------------------------------------------------
  #A3F2C1 这样的颜色值,拆开是三组两位十六进制:
    A3  F2  C1  ->  红 163,绿 242,蓝 193
  每组两位十六进制,范围正好是 0 到 255,也就是 8 位二进制。
  三个 255 是纯白 #FFFFFF,三个 0 是纯黑 #000000。
  这一条能解释很多日常现象:为什么颜色值总是 6 位、
  为什么「16 位色」叫这个名字——都是二进制位数换了个说法。

①bin、oct、hex 都带前缀(0b、0o、0x)。要纯数字就用 [2:] 切掉前面两个字符。 ②第三段反过来:把三种写法的字面量直接打印,出来都是 173。同一个数,四种写法,值一样。 ③int(c[i:i+2], 16) 是「按十六进制解析这两个字符」。第二个参数就是进制,换成 2 就是按二进制解析。 ④最后一行两个数:255 和 765。255 是 8 位二进制能表示的最大值,所以每个颜色通道最多就到这儿。

30 秒实验

  1. 把 255 写成二进制,看是不是正好八个 1。
  2. 把 #000000 和 #FFFFFF 各拆一遍,验证是 0 和 255。
  3. 试一下 int('1010', 2) 和 int('1010', 16),看两个结果差多少。

常见误区

  1. 「二进制、八进制、十六进制是三种不同的数。」是同一个数的三种写法。
  2. 「电脑里存的是十六进制。」存的还是 0 和 1,十六进制只是给人看的缩写。
  3. 「颜色值 6 位是随便定的。」三组各两位,每组 8 位二进制,所以是 6 位。
自测三问(点开对答案) 1. 为什么电脑内部只用二进制? —— 一根线只有通电和不通电两种状态。档位越多越容易被干扰分不清。 2. 十六进制为什么好读? —— 每四位二进制正好对应一位十六进制,转换时照表抄,不用算。 3. 颜色值里每个通道为什么最大是 255? —— 每个通道占 8 位二进制,8 位全 1 就是 255。

写法认清了,接下来要会换。下一节讲两件手工活:除二取余 和 按位权展开。

相关笔记