跳转至

数制、补码、浮点数与字符

进位制:位置决定权重

\(b\) 进制的 \(n\) 位数可写为:

\[ (d_{n-1}\cdots d_1d_0)_b=\sum_{i=0}^{n-1}d_i b^i. \]

二进制适合两种稳定电平,十六进制则把每 4 位二进制压成一个符号,便于人阅读。比如:

\[ (10110110)_2=(\mathrm{B6})_{16}=182. \]

转换时不要把十六进制当成另一种数据,只是同一位串的紧凑写法。

无符号数与模运算

\(n\) 位无符号数范围为 \(0\)\(2^n-1\)。硬件加法器自然丢弃第 \(n+1\) 位进位,因此运算等价于模 \(2^n\)

\[ (a+b)_{hardware}=(a+b)\bmod 2^n. \]

8 位无符号数中,\(250+10\) 得到 \(4\)。这不是加法器算错,而是结果超出编码范围。

补码为何统一加减法

\(n\) 位补码把负数 \(-x\) 编码为 \(2^n-x\)。因此减法可变成加法:

\[ a-b\equiv a+(2^n-b)\pmod {2^n}. \]

例如 8 位中 \(-5\) 的编码为:

 5        = 00000101
按位取反 = 11111010
再加 1   = 11111011

计算 \(7+(-5)\)

00000111
11111011
---------
00000010   # 最高进位丢弃

补码范围不对称:

\[ -2^{n-1}\le x\le 2^{n-1}-1. \]

所以最小负数没有对应的正数。两个同号数相加却得到异号结果,说明有符号溢出;无符号溢出则看最高位进位,两种判断不能混用。

定点数与浮点数

定点数约定小数点位置固定,硬件简单、误差可预测,常用于金额和嵌入式控制。浮点数用科学计数法换取更大动态范围。

IEEE 754 单精度由 1 位符号、8 位阶码和 23 位尾数组成。正规数的值为:

\[ (-1)^s\times (1.f)_2\times 2^{e-127}. \]

隐藏的前导 \(1\) 提高了一位有效精度。全零阶码用于零和非正规数,全一阶码用于无穷与 NaN。

为什么 0.1 + 0.2 不一定等于 0.3

\(0.1\) 在二进制中是无限循环小数,只能舍入到有限尾数。每次运算还要对阶、计算和再次舍入。因此浮点数近似实数,却不满足实数运算的全部代数律,例如:

\[ (a+b)+c\ne a+(b+c) \]

在浮点计算中完全可能成立。扩大位数会减小误差,但不能消灭有限表示的根本限制。

字符:从字符集到字节编码

字符集回答“每个字符对应哪个码点”,编码回答“码点怎样变成字节”。ASCII 用 7 位覆盖基础英文字符。Unicode 为跨语言字符分配统一码点,UTF-8 再用 1 到 4 个字节变长编码这些码点。

UTF-8 与 ASCII 的前 128 个字符兼容,并让常见英文文本紧凑;代价是“字符数”不等于“字节数”,字符串随机定位更复杂。字形、字符、码点和字节是四个不同层次,乱码通常来自编码契约不一致。

选择表示的权衡

表示 优点 代价与限制
无符号整数 范围全部用于非负数 不能直接表达负数
补码整数 加减硬件统一 范围有限且不对称
定点数 可预测、实现简单 动态范围有限
浮点数 动态范围大 舍入、特殊值、运算非结合
UTF-8 兼容 ASCII、跨语言 变长,字符处理更复杂

自测

  1. 写出 8 位补码中 \(-128\)\(127\) 的编码,解释为何没有 \(+128\)
  2. 何时应优先用定点数而不是浮点数?
  3. Unicode 码点和 UTF-8 字节序列有什么区别?