初赛专题(二):编码与数的表示 —— 进制、补码、溢出与字符编码

本讲定位:CSP-J 初赛系列的知识重头讲。七年真题统计(见 cspj-exam-analysis-2019-2025.md):进制转换类选择题七年六出;2024、2025 连续两年开卷第 1 题考”32 位 int/unsigned 的取值范围”——数据类型范围已从冷知识变成固定送分题;溢出、char 符号、浮点精度是阅读程序判断题五大陷阱之一”溢出与数据类型”的弹药库(2021 负数补码、2022 mid*mid 溢出、2023 浮点精度,年年有份)。本讲把”数和字符在机器里长什么样”一次讲透。

本讲是下一讲(位运算)的地基:不懂补码,就解释不了 x & -x 在负数下的行为;不熟二进制,位运算技巧只能死记。两讲连着学。

前置知识:整数四则运算、%/ 运算符。

适合对象:CSP-J 初赛。标注 ⭐ 的小节为进阶内容,第一遍学习可以跳过。


1. 进制:同一个数的不同写法

1.1 按权展开:进制的定义

$k$ 进制就是”逢 $k$ 进一”:从右往左第 $i$ 位(从 0 数起)的是 $k^i$。写作 $(a_m \dots a_1 a_0)_k$ 的数,值为

$$ (a_m \dots a_1 a_0)_k = a_m \cdot k^m + \dots + a_1 \cdot k^1 + a_0 \cdot k^0 $$

初赛常用的四种进制与书写习惯:

进制 数码 C++ 字面量写法
二进制 0, 1 0b1100100 $(1100100)_2 = 100$
八进制 0~7 前导 0:0144 $(144)_8 = 100$
十进制 0~9 100 100
十六进制 0~9, A~F 0x64 $(64)_{16} = 100$

十六进制的 A~F 代表 10~15。C++ 里前导 0 的整数是八进制——010 是 8 不是 10,选择题的经典冷箭。

1.2 k 进制 → 十进制:按权展开硬算

$(2A3)_{16} = 2 \times 256 + 10 \times 16 + 3 = 675$。没有任何技巧,权乘数码求和即可。考场上二进制转十进制建议直接背 2 的幂:$1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024$(背到 $2^{10}$,再记住 $2^{16} = 65536$、$2^{31} \approx 2.1 \times 10^9$ 两个锚点)。

1.3 十进制 → k 进制:除基取余,倒着读

不断除以 $k$、记录余数,直到商为 0,余数从下往上读

$$ 100 \div 2 = 50 \cdots 0,\quad 50 \div 2 = 25 \cdots 0,\quad 25 \div 2 = 12 \cdots 1,\quad 12 \div 2 = 6 \cdots 0, $$

$$ 6 \div 2 = 3 \cdots 0,\quad 3 \div 2 = 1 \cdots 1,\quad 1 \div 2 = 0 \cdots 1 $$

从下往上:$100 = (1100100)_2$。为什么倒着读?第一次除得到的余数是”个位”(权最小),最后一次是最高位。

小数部分(简要,选择题偶考):乘基取整,正着读。$0.625 \times 2 = 1.25$ 取 1;$0.25 \times 2 = 0.5$ 取 0;$0.5 \times 2 = 1.0$ 取 1——$0.625 = (0.101)_2$。有的十进制小数二进制写不完(见第 5 节浮点数),如 $0.1 = (0.000110011\overline{0011}\dots)_2$ 无限循环。

1.4 二 ↔︎ 八/十六:分组秒转

因为 $8 = 2^3$、$16 = 2^4$,二进制从右往左每 3 位对应一位八进制、每 4 位对应一位十六进制,不够补前导零: