# 2.2不同进制间的转换

## 阅读入口

* [进制转换](/knowledge/cs/data-representation/number-base-conversion/)

## 位权与进制记号

一个 $r$ 进制数（$r\ge 2$，$r$ 为整数）把数值写成数码串，每一位的数码取自 $0,1,\dots,r-1$，数码所在的位置决定它的**位权**。若整数部分有 $n$ 位、小数部分有 $m$ 位，则

$$
(b_{n-1}\cdots b_1b_0.b_{-1}\cdots b_{-m})_r
=\sum_{i=-m}^{n-1}b_i r^i .
$$

第 $i$ 位的位权是 $r^i$：小数点左边从最低位起依次为 $r^0,r^1,r^2,\dots$，小数点右边依次为 $r^{-1},r^{-2},\dots$。最高位记作MSB，最低位记作LSB。

下标 $r$ 标注底数，十进制常省略下标。不写下标时，同一串数码可能对应不同的值：

$$
(1011)_2=11,\qquad (1011)_8=521,\qquad (1011)_{16}=4113 .
$$

| 进制   | 底数   | 可用数码                                 |
| :--- | :--- | :----------------------------------- |
| 二进制  | $2$  | $0,1$                                |
| 八进制  | $8$  | $0\sim 7$                            |
| 十进制  | $10$ | $0\sim 9$                            |
| 十六进制 | $16$ | $0\sim 9$，$A\sim F$ 分别表示 $10\sim 15$ |

[来源：进制转换](/knowledge/cs/data-representation/number-base-conversion/#definition)

进制写法统一用下标标明底数，十进制省略。题目中的数码常常不带下标，作答前先按题目指定的进制读。

## 换算的四个方向

### $r$ 进制转十进制

按位权展开，把每一位的数码乘以该位的位权后相加。整数部分用正幂，小数部分用负幂。

### 十进制整数转 $r$ 进制

1. **除以 $r$，记下余数**

   用当前整数除以 $r$，余数就是当前最低位的数码。

2. **用商继续**

   把商作为新的整数，重复上一步，直到商为 $0$。

3. **逆序读取余数**

   最先得到的余数是最低位，最后得到的是最高位，从下往上读。

### 十进制小数转 $r$ 进制

1. **乘以 $r$**

   用当前小数部分乘以 $r$。

2. **取出整数部分**

   乘积的整数部分是当前小数位的数码，剩下的小数部分进入下一轮。十六进制中整数部分 $10\sim 15$ 要写成 $A\sim F$。

3. **重复到终止**

   直到小数部分变为 $0$，或达到所需精度。取出的数码按先后顺序从左到右写出。

> [!TIP]
> 大多数十进制小数不能写成有限位的二进制小数。例如 $0.1$ 的二进制展开是 $0.0001100110011\ldots_2$，乘 $2$ 的过程不会终止；此时只能按精度截断，截断会带来舍入误差。

### 二进制与八进制、十六进制互转

以小数点为界，整数部分向左、小数部分向右分组：八进制每 $3$ 位一组，十六进制每 $4$ 位一组，每组换成对应的 $1$ 位八进制或十六进制数码。反方向转换时，把每一位八进制数码写成 $3$ 位二进制数、每一位十六进制数码写成 $4$ 位二进制数，再以小数点为界拼接，去掉整数部分的前导 $0$ 和小数部分的末尾 $0$。

> [!WARNING]
> **补 $0$ 的方向**
>
> 不足一组时，整数部分在左端补 $0$，小数部分在右端补 $0$。补 $0$ 只影响分组，不改变数值；把方向弄反会直接算错。

八进制与十六进制的小数同样按位权展开，权分别为 $8^{-1},8^{-2},\dots$ 与 $16^{-1},16^{-2},\dots$。它们与十进制小数互转时，通常先换成二进制，再用分组法处理。

### 数位对应表

| 十进制 |  二进制 | 八进制 | 十六进制 |
| :-: | :--: | :-: | :--: |
|  0  | 0000 |  0  |   0  |
|  1  | 0001 |  1  |   1  |
|  2  | 0010 |  2  |   2  |
|  3  | 0011 |  3  |   3  |
|  4  | 0100 |  4  |   4  |
|  5  | 0101 |  5  |   5  |
|  6  | 0110 |  6  |   6  |
|  7  | 0111 |  7  |   7  |
|  8  | 1000 |  10 |   8  |
|  9  | 1001 |  11 |   9  |
|  10 | 1010 |  12 |   A  |
|  11 | 1011 |  13 |   B  |
|  12 | 1100 |  14 |   C  |
|  13 | 1101 |  15 |   D  |
|  14 | 1110 |  16 |   E  |
|  15 | 1111 |  17 |   F  |

[来源：进制转换](/knowledge/cs/data-representation/number-base-conversion/#methods)

本节按“二进制与十进制 → 小数 → 二进制与八、十六进制”的次序展开。整数和小数的两个终止条件不同，下面的课程约定单独列出。

## 学习安排

本节先讲二进制与十进制的整数互转，再加入小数，最后用 $8=2^3$、$16=2^4$ 把八进制和十六进制接到二进制上。按这个顺序学习，八进制与十六进制就是二进制分组后的另一种写法。

* 先练按权展开，确认位权从 $2^0$ 开始向两侧延伸；再练除 $2$ 取余和乘 $2$ 取整。
* 对应表不必死背，考试时按 $3$ 位、$4$ 位分组现场推出即可；但 $0\sim 15$ 与A～F的对应要能快速写出。
* 教材的两个Python程序分别对应“位权逐位折半”和“余数插到列表头部”，读代码时把这两步和手算步骤对上。
* 本节只处理表示与换算；二进制四则运算、补码和浮点数留到下一节。

## 课程约定

* 进制用下标书写，例如 $(1101)_2$，十进制省略下标。作答时要标清进制，否则同一串数码可能被读成不同的值。
* 整数部分除到商为 $0$ 为止；小数部分乘到小数部分为 $0$，或乘到题目要求的精度为止。两个终止条件分别用于整数和小数，不能混用。
* 分组换算以小数点为界，整数部分向左分组，小数部分向右分组。

## 易错点

* 补 $0$ 只发生在分组时：整数在左端补，小数在右端补，方向弄反会直接算错。
* 除 $2$ 取余时，最先得到的余数是最低位，必须从下往上读。
* 像 $0.1$ 这样的十进制小数，二进制展开是无限循环的，只能按精度截断。
* 八进制、十六进制与十进制之间没有逐位对应关系，只有它们与二进制之间才能按 $3$ 位或 $4$ 位分组。
