👋 欢迎来到二进制系统!

欢迎来到计算机科学最基础的构建模块!本章“二进制数系统”是你探索数据表示(Representing Data)旅程的一部分。计算机所做的一切——从显示一张照片到运行复杂的计算——归根结底都是由“1”和“0”组成的。

如果数学不是你最擅长的科目,请不要担心。我们将拆解这些概念,对比不同的数字系统(二进制、十进制、十六进制),并学习计算机处理负数和小数等棘手问题时所使用的巧妙技巧。让我们开始吧!

1. 基础:进位制与单位 (3.5.1 & 3.5.2)

1.1 理解不同的进位制(十进制、二进制、十六进制)

我们习惯使用十进制(Decimal),即10进制来计数。然而,计算机依靠电流(通或断)工作,因此它们使用二进制(Binary),即2进制

  • 十进制 (Base 10): 使用10个数字(0–9)。每一位代表10的幂(个位、十位、百位、千位……)。
  • 二进制 (Base 2): 仅使用2个数字(0和1)。每一位代表2的幂(1, 2, 4, 8, 16……)。这些单独的数字被称为位(Bits)
  • 十六进制 (Base 16): 使用16个符号(0–9 和 A–F)。该系统是二进制的缩写,使得程序员更容易阅读冗长的二进制字符串。

你知道吗?“十六进制”中的 A=10, B=11, C=12, D=13, E=14, F=15。

1.2 信息单位

信息的基本单位是位(Bit)(单个0或1)。然而,数据通常是以组为单位进行处理的:

  • 字节(Byte) 是8个位的组合。
  • 用 \(n\) 位可以表示的唯一值的数量是 \(2^n\)。
    例如:用3位,你可以表示 \(2^3 = 8\) 个不同的值(从 000 到 111)。

1.3 二进制与十进制前缀(“千”的争议)

在讨论计算机存储大小时,我们使用前缀,但有两种不同的类型:

二进制前缀(2的幂) - 用于存储/内存:

这些基于 \(2^{10}\) (1024) 的幂。它们通常用于精确定义内存大小。

  • Kibi (Ki): \(2^{10}\) (1,024)
    (例如:1 KiB = 1024 Bytes)
  • Mebi (Mi): \(2^{20}\) (1,048,576)
  • Gibi (Gi): \(2^{30}\)
  • Tebi (Ti): \(2^{40}\)
十进制前缀(10的幂) - 用于通信速度:

这些是我们在数学和科学中使用的标准前缀,基于 \(10^3\) (1000) 的幂。

  • kilo (k): \(10^3\) (1,000)
    (例如:1 kB = 1000 Bytes)
  • mega (M): \(10^6\) (1,000,000)
  • giga (G): \(10^9\)
  • tera (T): \(10^{12}\)

核心要点: 计算机以二进制(2进制)进行通信。十六进制(16进制)是人类友好的速记法。在讨论数据容量时,请记住 Kibi (\(2^{10}\)) 与 kilo (\(10^3\)) 的区别。

1.4 不同进位制间的转换

虽然转换通常不会作为独立的考点,但你需要能够在其他主题(如浮点数或汇编语言)中运用它们。

十进制转二进制(例如:将 42 的十进制转换为二进制)
  1. 找出小于等于42的最大2的幂(是32)。在该位上写1。
  2. 用42减去32。余数为10。
  3. 检查下一个2的幂(16)。16能放入10吗?不能。写0。
  4. 检查8。8能放入10吗?能。写1。余数为2。
  5. 检查4。4能放入2吗?不能。写0。
  6. 检查2。能。写1。余数为0。
  7. 检查1。不能。写0。


4210 = 001010102(8位表示)

二进制转十六进制(快速方法)
  1. 从右向左将二进制数字每4位分成一组(每4位一组称为一个“半字节”,正好对应一个十六进制数字)。
  2. 将每组转换成对应的十六进制。

例如:10110011
第1组:1011 (8 + 2 + 1) = 11。在十六进制中,这是 B
第2组:0011 (2 + 1) = 3。在十六进制中,这是 3
结果:101100112 = B316

2. 表示正整数:无符号二进制 (3.5.3.1)

2.1 无符号二进制与有符号二进制

无符号二进制(Unsigned Binary)是最简单的形式,其中所有位都用于表示正数的大小。它无法表示负值。

有符号二进制(Signed Binary)(稍后介绍)保留一位(通常是最高有效位,即MSB)来指示该数是正数还是负数。

2.2 无符号整数的范围

如果有 \(n\) 位,在无符号二进制中可表示的值范围是:

最小值:0
最大值:\(2^n - 1\)

例如:使用8位 (\(n=8\))
最大值:\(2^8 - 1 = 256 - 1 = 255\)。
范围:0 到 255。

2.3 无符号二进制算术 (3.5.3.2)

二进制加法和乘法遵循与十进制算术相似的规则,但只有在和为2或更大时才进位1。

二进制加法规则:
  • 0 + 0 = 0
  • 0 + 1 = 1
  • 1 + 1 = 0(进位1)
  • 1 + 1 + 1(进位输入) = 1(进位1)

加法示例 (12 + 5 = 17):

   1 1 0 0 (12)
+   0 1 0 1 (5)
-----
1 0 0 0 1 (17)

常见错误: 进行算术运算时,如果结果所需的位数超过了分配的位数,就会发生溢出错误(overflow error)(在第5节介绍)。

核心要点: 无符号二进制很简单,仅代表正数,最大值总是 \(2^n - 1\)。

3. 表示负整数:补码 (3.5.3.3)

补码(Two's Complement)是你需要掌握的唯一有符号二进制表示法。它允许计算机使用标准的加法电路进行减法运算,从而简化了硬件设计。

3.1 识别符号

在补码中:

  • 最高有效位 (MSB)(最左边的位)指示符号。
  • 如果 MSB 是 0,则该数为正数。
  • 如果 MSB 是 1,则该数为负数。

3.2 补码整数的范围

由于有一位被保留用于符号位,对于相同的位数,其最大范围比无符号二进制小。

对于 \(n\) 位,其范围是:

最大正值:\(2^{n-1} - 1\)
最小负值:\(-2^{n-1}\)

例如:使用8位 (\(n=8\))
最大正值:\(2^7 - 1 = 127\)。
最小负值:\(-2^7 = -128\)。
范围:-128 到 +127。

3.3 将负十进制转换为补码二进制

分步技巧(“按位取反加1”法):

目标:用8位表示 -5。

  1. 找到正数的二进制: +5 的8位二进制是 0000 0101。
  2. 按位取反(翻转): 将所有的0变为1,所有的1变为0(这称为反码)。
    0000 0101 变为 1111 1010。
  3. 结果加1:
    1111 1010 + 1 = 1111 1011
    这就是 -5 的补码表示。(注意 MSB 为 1,表示这是一个负数)。

3.4 使用补码进行减法

补码的神奇之处在于减法 (A - B) 等同于加法 (A + (-B))。

示例:计算 12 - 5(使用8位)

  1. 表示 12:      0000 1100
  2. 表示 -5:      1111 1011(来自3.3步)
  3. 相加:

      0000 1100 (+12)
    + 1111 1011 (-5)
    ----------
    (1) 0000 0111 (+7)

如果计算结果在分配的位数内,最终的进位(1)将被忽略。结果 0000 0111 即为 7,这是正确的。

核心要点: 补码使计算机能够表示负数,并利用加法电路完成减法。MSB 决定了符号。

4. 表示分数 (3.5.3.4, 3.5.3.8, 3.5.3.9)

为了表示带有小数部分的数字(实数),计算机主要使用两种方法:定点数(Fixed Point)浮点数(Floating Point)

4.1 定点数表示法

在定点数中,二进制点的位置是预先确定的,保持“固定”。

  • 我们分配固定的位数给整数部分(点左侧),分配固定的位数给小数部分(点右侧)。
  • 点右侧使用的幂是2的负幂:\(2^{-1}\) (0.5), \(2^{-2}\) (0.25), \(2^{-3}\) (0.125) 等。

示例(4位整数,4位小数):
1 0 1 1 . 0 1 0 0
\( (8+0+2+1) . (0.25) \) = 11.25

4.2 浮点数表示法(简化版)

浮点数是计算机版本的科学计数法(例如 \(6.022 \times 10^{23}\))。二进制点“浮动”以最大化表示的有效数字。

浮点数由两个主要部分组成,通常都使用补码表示:

  1. 尾数 (Mantissa, M): 表示数字的有效数字(精度)。
  2. 指数 (Exponent, E): 表示尾数所乘的2的幂(范围)。

其值计算公式为: \( M \times 2^E \)

4.2.1 范围 vs. 精度

位数在尾数和指数之间的分配方式决定了系统的能力:

  • 精度:尾数的位数决定。尾数位数越多 = 数字表示越精确(舍入误差越小)。
  • 范围:指数的位数决定。指数位数越多 = 存储极大或极小数字的能力越强。
4.2.2 规范化 (3.5.3.9)

为了确保每个数字都有唯一的表示并最大化精度,浮点数必须进行规范化(Normalisation)

为什么规范化? 为了将二进制点固定在一个标准位置,从而消除冗余的零。

规范化规则: 尾数必须以“01...”开头(正数)或“10...”开头(负数)。

如何规范化(步骤):

  1. 移动二进制点,直到尾数以 01(正)或 10(负)开头。
  2. 更新指数以反映你移动点的位数。

示例:非规范化的正数 001100 \(\times 2^2\)(6位尾数,4位指数)
1. 将点向右移动1位:0.1100。
2. 新指数:\(2^2\) 变为 \(2^{2-1} = 2^1\)。
结果:011000 \(\times 2^1\)。(开头的0是符号位,点后的第一个数字是 '1',满足 01... 的要求)。

4.3 定点数与浮点数的对比 (3.5.3.8)

定点数 浮点数
范围 非常有限。 非常大(由指数决定)。
精度 恒定但有限(由小数位数决定)。 高(由尾数决定)。
速度 计算速度更快(算术简单)。 计算速度较慢(需要复杂硬件进行移位/规范化)。
用途 简单的财务系统(精度必须固定)。 科学建模、图形处理、大规模计算。

核心要点: 浮点数提供了巨大的范围(指数)和良好的精度(尾数),但定点数在数字大小差异不大的计算中更简单、更快捷。

5. 表示的局限性与错误 (3.5.3.5, 3.5.3.6, 3.5.3.7)

5.1 舍入误差(不精确性) (3.5.3.5)

二进制系统无法精确表示所有十进制分数,就像我们在十进制中无法完美写出 1/3(结果是 0.3333...)一样。

  • 一个十进制数(如 0.1)可能需要无限多的二进制位才能完全精确。
  • 由于计算机使用固定的位数(精度受限),它必须截断或舍入,这会导致小的舍入误差(Rounding Errors)

5.2 绝对误差与相对误差 (3.5.3.6)

当计算不准确时,我们需要一种方法来衡量误差:

  • 绝对误差: 真值与表示值之间的实际差异。
    公式:\( | \text{真值} - \text{存储值} | \)
  • 相对误差: 绝对误差除以真值(以百分比或分数表示)。这通常更有用,因为它显示了相对于数字大小的误差。
    公式:\( \frac{\text{绝对误差}}{\text{真值}} \)

例如:如果真值是 200,100 的绝对误差非常大(50%相对误差);但如果真值是 1,000,000,它就非常小(0.01%相对误差)。

5.3 溢出与下溢 (3.5.3.7)

这些错误发生在计算结果超出了所分配位数可表示的范围时。

  • 溢出 (Overflow): 当结果太大(太正或太负)而无法存储在可用位数中时发生。

    想象一下试图在一个8位无符号系统(最大255)中存储300,这就会溢出。

  • 下溢 (Underflow): 当结果太接近于零而无法精确表示时发生,意味着系统能存储的最接近的值是0。

    这种情况主要发生在极小的浮点数计算中,此时指数太小,无法处理。

核心要点: 计算机使用有限的位数,这导致了固有的局限性(舍入误差)。溢出和下溢错误定义了系统表示范围的边界。

🧠 复习检查清单

  • 我能进行二进制、十进制和十六进制之间的转换吗?
  • 我能计算n位无符号数的范围吗?(0 到 \(2^n - 1\))
  • 我能计算n位有符号数的范围吗?(\(-2^{n-1}\) 到 \(2^{n-1} - 1\))
  • 我能使用补码来表示负数并执行减法吗?
  • 我理解在浮点数中,尾数控制精度,指数控制范围吗?
  • 我能解释什么是规范化以及为什么它很重要吗?
  • 我清楚溢出(太大)和下溢(太接近于零)的区别吗?

恭喜!你已经掌握了计算机内部数字管理的核心概念。继续练习那些进位制转换和补码计算步骤吧!