第一讲 · 数制与数据表示

对应材料:2025 计组复习提纲“数制:数据的表示”,并参考课程概述中关于抽象层次的说明。

计算机里并没有一个天然的“整数”或“小数”。硬件真正保存的只有一串高低电平;我们先约定一种编码规则,再按这条规则解释比特。于是,同一个 11111111 可以是无符号数 255255、补码整数 −1-1,也可以只是一个字节的数据。

这一讲要解决的核心问题不是“背编码”,而是:给定有限位数,怎样表示数、怎样运算、什么时候会失真。

1. 位权:所有进位制都在做同一件事

在基数为 rr 的进位制中,

(dndn−1⋯d0.d−1d−2⋯ )r=∑idiri,0≤di<r.(d_nd_{n-1}\cdots d_0.d_{-1}d_{-2}\cdots)_r =\sum_i d_i r^i, \qquad 0\le d_i<r.

例如:

(101101.011)2=1×25+1×23+1×22+1×20+1×2−2+1×2−3=45.375.(101101.011)_2 =1\times2^5+1\times2^3+1\times2^2+1\times2^0 +1\times2^{-2}+1\times2^{-3} =45.375.

1.1 十进制整数转二进制

不断“除以 2 取余”,余数从后往前写。以 4545 为例:

45 ÷ 2 = 22 ... 1
22 ÷ 2 = 11 ... 0
11 ÷ 2 =  5 ... 1
 5 ÷ 2 =  2 ... 1
 2 ÷ 2 =  1 ... 0
 1 ÷ 2 =  0 ... 1

因此 45=(101101)245=(101101)_2。

1.2 十进制小数转二进制

不断“乘 2 取整数部分”,整数部分按出现顺序写。以 0.3750.375 为例:

0.375 × 2 = 0.75  → 0
0.75  × 2 = 1.5   → 1
0.5   × 2 = 1.0   → 1

所以 0.375=(0.011)20.375=(0.011)_2。

1.3 二进制、八进制、十六进制快速互转

  • 每 3 位二进制对应 1 位八进制;
  • 每 4 位二进制对应 1 位十六进制;
  • 分组从小数点向两边展开,不足位补 0。

例如:

(1101 1010 0111)2=(DA7)16.(1101\ 1010\ 0111)_2=(\mathrm{DA7})_{16}.

十六进制只是二进制的紧凑写法,并没有改变底层比特。

2. 无符号数:所有位都贡献数值

nn 位无符号数的范围是

0≤x≤2n−1.0\le x\le 2^n-1.

例如 8 位无符号数的范围是 0∼2550\sim255。加法只保留低 nn 位,本质上是在模 2n2^n 的环上运算:

250+10=260≡4(mod256).250+10=260\equiv4\pmod{256}.

硬件得到 00000100;如果程序把它解释为普通自然数,就发生了无符号溢出。

3. 有符号整数:为什么最终选择补码

3.1 原码、反码、补码

设机器字长为 nn。对正数,三种编码相同;对负数:

  • 原码:最高位表示符号,其余位表示绝对值;
  • 反码:对应正数编码逐位取反;
  • 补码:反码加 1。

8 位编码中,+5+5 与 −5-5 为:

表示+5+5−5-5
原码0000010110000101
反码0000010111111010
补码0000010111111011

若总位宽为 nn:

编码可表示范围零的个数
原码−(2n−1−1)∼2n−1−1-(2^{n-1}-1)\sim 2^{n-1}-12
反码−(2n−1−1)∼2n−1−1-(2^{n-1}-1)\sim 2^{n-1}-12
补码−2n−1∼2n−1−1-2^{n-1}\sim 2^{n-1}-11

原码和反码都有 +0、-0 两个零,而且加减时需要单独处理符号。补码把正负数统一放进模 2n2^n 运算:

−x≡2n−x(mod2n).-x\equiv 2^n-x\pmod{2^n}.

于是,同一套加法器也能做减法:

A−B=A+(−B)=A+(B‾+1).A-B=A+(-B)=A+(\overline B+1).

这就是硬件偏爱补码的根本原因,不只是“计算规则方便背”。

3.2 补码的范围不对称

nn 位补码范围为

−2n−1≤x≤2n−1−1.-2^{n-1}\le x\le 2^{n-1}-1.

8 位补码范围是 −128∼127-128\sim127。负数一侧多出来的 10000000 表示 −128-128;它没有对应的 +128+128。所以对最小负数取相反数仍会溢出。

3.3 快速读补码

若最高位为 0,直接按无符号数读。若最高位为 1,可用两种方法:

  1. 逐位取反再加 1,所得绝对值前加负号;
  2. 最高位权看作 −2n−1-2^{n-1},其余位权照常相加。

例如:

(11111011)2=−27+26+25+24+23+21+20=−5.(11111011)_2=-2^7+2^6+2^5+2^4+2^3+2^1+2^0=-5.

3.4 移码

移码给真值统一加一个偏置。若总位宽为 nn,常用偏置 2n−12^{n-1}:

[x]bias=x+2n−1.[x]_{bias}=x+2^{n-1}.

它让编码按无符号数从小到大排列时,真实值也从负到正递增,特别适合比较阶码。IEEE 754 的指数也采用偏置思想;单精度使用 127 而非 128,并把全 0、全 1 阶码留给特殊值。

4. 溢出与进位不是同一件事

无符号运算看最高位的进位;有符号补码运算看结果是否超出有符号范围。加法中,两个同号数相加却得到异号结果,就是有符号溢出。

对最高位的输入进位 Cn−1C_{n-1} 与输出进位 CnC_n,也可写成

V=Cn−1⊕Cn.V=C_{n-1}\oplus C_n.

以 8 位为例:

01111111   (+127)
+00000001  (+1)
---------
10000000   (-128, 若按补码解释)

这里没有得到数学上的 128128,而是发生有符号溢出。反过来,11111111 + 00000001 = 00000000 有最高位进位;按无符号数解释是溢出,按补码解释却是 −1+1=0-1+1=0,没有有符号溢出。

5. 定点数:小数点位置由约定决定

定点数并不真的保存小数点,而是约定它在固定位置。若一个 nn 位补码整数实际代表的值为 X/2fX/2^f,就称有 ff 个小数位。

例如 8 位编码 01100000:

  • 按整数解释是 9696;
  • 若约定 7 个小数位,则是 96/128=0.7596/128=0.75。

小数位越多,分辨率越高,但整数范围越小。这是固定总位宽下“范围与精度”的第一次权衡。

6. IEEE 754 单精度浮点数

32 位单精度分成三段:

字段位数含义
SS1符号位
EE8带偏置的阶码,偏置为 127
MM23小数部分,规格化数默认有隐藏的前导 1

对 1≤E≤2541\le E\le254 的规格化数:

x=(−1)S×(1.M)2×2E−127.x=(-1)^S\times(1.M)_2\times2^{E-127}.

6.1 编码示例:178.125178.125

178.125=(10110010.001)2=(1.0110010001)2×27.178.125=(10110010.001)_2=(1.0110010001)_2\times2^7.

因此:

  • S=0S=0;
  • E=7+127=134=(10000110)2E=7+127=134=(10000110)_2;
  • M=0110010001000⋯M=0110010001000\cdots。

最终编码为 0 10000110 01100100010000000000000,十六进制写作 0x43322000。

6.2 特殊值

阶码 EE尾数 MM含义
0000+0+0 或 −0-0
00非 0非规格化数,填补靠近 0 的范围
1∼2541\sim254任意规格化数
25525500+∞+\infty 或 −∞-\infty
255255非 0NaN,不是一个数

非规格化数没有隐藏的前导 1,其值为

(−1)S×(0.M)2×2−126.(-1)^S\times(0.M)_2\times2^{-126}.

6.3 浮点数为什么会不精确

像十进制的 0.20.2,在二进制中是无限循环小数,只能截断到有限位。浮点数的间隔还会随数量级增大:同样是相邻可表示数,靠近 21002^{100} 时的间距远大于靠近 1 时的间距。

因此浮点数运算要牢记:

  • 表示的是附近的一个可表示数,不一定是原实数;
  • 加法通常不满足结合律;
  • 直接判断两个计算结果“完全相等”可能不稳妥;
  • 位数固定后,范围和精度仍然互相牵制。

7. 非数值数据也是编码

课件还把逻辑值、字符和汉字列为非数值数据:

  • 布尔值通常用 0、1 表示假和真;
  • ASCII 用 7 位编码西文字符,例如字符 '0' 的编码不是数值 0;
  • 汉字需要字符集与编码方案,编码本身不等于字形。

理解这一点很重要:内存里不存在“天然字符串”。只有当程序知道编码、长度和边界时,那串字节才会被解释成文本。

8. 一条统一的解题路线

面对任何“这一串比特是什么”的题,按顺序问:

  1. 位宽是多少? 位宽决定模和范围。
  2. 按什么类型解释? 无符号、补码、定点还是浮点。
  3. 小数点或字段边界在哪里? 定点位置、IEEE 754 的 S/E/M 都是约定。
  4. 运算是否截断? 硬件通常只保留固定宽度。
  5. 检查哪一种溢出? 无符号进位与有符号溢出不能混用。

这五问会一直贯穿后面的 MIPS 指令、ALU、存储器和 Cache。

评论