介绍:为什么数制很重要

欢迎来到计算机科学数据表示的世界!这一章起初看起来可能纯粹是数学,但它却是计算机工作方式的绝对基石。为什么这么说?因为计算机既不会说英语,也不使用十进制(Base 10);它们使用的是二进制(Base 2)——即由 0 和 1 组成的序列。

理解数制及其转换,能让你清楚地看到数据是如何在处理器内部存储、操作和表示的。这些知识对于后续学习汇编语言、浮点数以及数据存储计算等主题至关重要。


1. 核心数制 (3.5.1)

1.1 十进制 (Base 10) – 我们日常使用的系统

我们每天都在使用十进制。它是十进制,因为它使用了 10 个唯一的数字(0 到 9)。

  • 基数 (Base): 10
  • 使用的数字: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9

我们通过位值表示法 (Positional Notation) 来理解数值,其中数字的位置决定了它的 10 的幂次方。
示例: 十进制数 459 实际上是:

$$4 \times 10^2 + 5 \times 10^1 + 9 \times 10^0$$

1.2 二进制 (Base 2) – 计算机的语言

计算机使用二进制,因为电子电路只能代表两种状态:开 (1) 或关 (0)。每一个 0 或 1 被称为一个位 (Bit)(二进制数字)。

  • 基数 (Base): 2
  • 使用的数字: 0, 1

二进制也使用位值表示法,但它是基于 2 的幂次方。
示例: 一个 8 位的二进制数使用以下列权重:

$$128, 64, 32, 16, 8, 4, 2, 1$$

1.3 十六进制 (Base 16) – 程序员的速记法

二进制字符串(如 110101100101)很快就会变得很长,人类读起来和记起来都很困难。十六进制 (Hex) 是二进制的一种便捷缩写。

  • 基数 (Base): 16
  • 使用的数字: 0-9 和 A-F

十六进制使用 16 个唯一的符号。由于我们只有 10 个数字,因此字母 A 到 F 被用来表示 10 到 15 的值。

十进制二进制 (4位)十六进制
000000
910019
101010A
151111F

2. 数制转换 (3.5.1)

你必须能够在这三种进制之间进行转换:十进制 (Base 10)、二进制 (Base 2) 和十六进制 (Base 16)。

2.1 二进制转十进制 (Base 2 转 Base 10)

这是最简单的转换:将每一位乘以其对应的 2 的幂次方,然后将结果相加。

步骤示例:将 \(101101_2\) 转换为十进制。

  1. 写出位置列标题(2 的幂次方,从右侧的 \(2^0 = 1\) 开始)。
  2. 将二进制数字填入对应的列中。
  3. 将所有出现 '1' 的对应列数值相加。
$2^5 (32)$$2^4 (16)$$2^3 (8)$$2^2 (4)$$2^1 (2)$$2^0 (1)$
101101

$$32 + 0 + 8 + 4 + 0 + 1 = 45$$

结果:\(101101_2 = 45_{10}\)

2.2 十进制转二进制 (Base 10 转 Base 2)

对于较大的数字,最可靠的方法是重复除以 2 法,并将余数逆序排列。

步骤示例:将 \(45_{10}\) 转换为二进制。

  1. 将十进制数除以 2。
  2. 记录余数(0 或 1)。
  3. 用商重复上述过程,直到商为 0。
  4. 从下(最高有效位 MSB)到上(最低有效位 LSB)读取余数。
除法运算余数 (位)
$45 \div 2$221
$22 \div 2$110
$11 \div 2$51
$5 \div 2$21
$2 \div 2$10
$1 \div 2$01

向上读取:101101。
结果:\(45_{10} = 101101_2\)

转换要点: 二进制与十六进制的转换对于理解数据的内部结构(如内存地址或指令代码)至关重要。

2.3 二进制与十六进制的转换

这种转换既直接又简单,因为 \(16 = 2^4\)。一个十六进制位恰好完美对应四个二进制位。

二进制转十六进制:四位一组

从右侧(LSB)开始,将二进制数字每四个分成一组。将每一组转换为对应的十六进制数。

示例:将 \(1101011011_2\) 转换为十六进制。

  1. 在左侧补零以凑满四位一组:0011 0101 1011
  2. 转换每一组:
    • $0011_2 = 3_{16}$
    • $0101_2 = 5_{16}$
    • $1011_2 = B_{16}$ (因为 $11_{10} = B_{16}$)
  3. 组合结果:35B

结果:\(1101011011_2 = 35B_{16}\)

十六进制转二进制:每一位展开

将每一个十六进制位转换为其对应的 4 位二进制序列。

示例:将 \(E7_{16}\) 转换为二进制。

  1. 转换 E:$E_{16} = 14_{10} = 1110_2$
  2. 转换 7:$7_{16} = 7_{10} = 0111_2$
  3. 组合结果:11100111

结果:\(E7_{16} = 11100111_2\)

快速回顾:转换小贴士

二进制 $\leftrightarrow$ 十六进制: 请务必使用 4 位分组快捷法。它快速且不易出错。

十进制转二进制: 使用重复除以 2 法,并向上读取余数。

二进制转十进制: 写出 2 的幂次方列标题(128, 64, 32, 16, 8, 4, 2, 1),并将位置为 '1' 的数值相加。


3. 信息单位 (3.5.2)

3.1 位与字节

最小的信息单位是位 (Bit, b)。一位存储一个 0 或 1。

计算机内存和存储中使用的基本单位是字节 (Byte, B)

  • 一个字节是由 8 位组成的。
  • 一个字节可以表示 \(2^8 = 256\) 种不同的值(从 0 到 255)。

3.2 \(2^n\) 规则

如果你有 \(n\) 位,总共可以表示 \(2^n\) 种不同的值。

你知道吗? 计算机系统中可寻址的内存总量也取决于地址总线的位数(例如,32 位地址总线可以访问 \(2^{32}\) 个位置)。

示例:

  • 2 位可以表示 \(2^2 = 4\) 种值(00, 01, 10, 11)。
  • 3 位可以表示 \(2^3 = 8\) 种值(000 到 111)。
  • 16 位可以表示 \(2^{16} = 65,536\) 种值。

3.3 十进制前缀 vs. 二进制前缀

在讨论存储容量(KB, MB 等)时,存在两种基于 10 的幂次方或 2 的幂次方的系统。区分标准的十进制前缀(kilo, mega)和二进制前缀(kibi, mebi)至关重要。

十进制前缀(10 的幂次方)

这些是数学和大多数存储制造商(如硬盘)使用的标准单位。

名称符号10 的幂次方近似值
kilok$10^3$1,000
megaM$10^6$1,000,000
gigaG$10^9$1,000,000,000
teraT$10^{12}$$10^{12}$

示例:1 kB (kilobyte) = $10^3$ 字节 (1,000 字节)

二进制前缀(2 的幂次方)

这些前缀被计算机系统用来指代内存和数据大小,因为计算机的一切都是基于 2 的幂次方的。标准的二进制前缀在中间加入了 "bi"(kibi, mebi, gibi, tebi)。

名称符号2 的幂次方精确值
kibiKi$2^{10}$1,024
mebiMi$2^{20}$1,048,576
gibiGi$2^{30}$$2^{30}$
tebiTi$2^{40}$$2^{40}$

示例:1 KiB (kibibyte) = $2^{10}$ 字节 (1,024 字节)

类比: 把这想象成测量长度。十进制的 kilo 刚好是 1000 米,而二进制的 kibi 稍微长一点,是 1024 米。


4. 用二进制表示整数 (3.5.3)

4.1 无符号二进制 (3.5.3.1)

无符号二进制 (Unsigned binary) 用于表示正整数(和零)。术语“无符号”意味着没有专门的位来指示数字是正还是负。

  • 所有的位都对数字的大小做出贡献。
  • 最小值始终为 0。
  • 对于 \(n\) 位,最大值为 \(2^n - 1\)。

示例: 在 8 位无符号二进制中,范围是 0 到 \(2^8 - 1\)(即 0 到 255)。

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

二进制加法

二进制加法遵循简单的规则,就像十进制加法一样,但在和达到 2 时会发生进位。

$A$$B$进位
0000
0110
1010
1101 (进位 1)
1 + 1 + 进位 111 (进位 1)

示例:在 4 位中进行 \(5_{10} + 3_{10}\)

   1  1  0  0 <-- 进位
     0  1  0  1  (5)
+    0  0  1  1  (3)
-----------------
     1  0  0  0  (8)
处理溢出

如果加法的结果超出了分配的位数的最大范围,就会发生溢出 (Overflow)。这个额外的位会丢失,导致结果错误。
示例: 在 4 位无符号二进制中添加 \(15 + 1\):

     1  1  1  1  (15)
+    0  0  0  1  (1)
-----------------
(1)  0  0  0  0  (0 - 错误!)

第 5 位(1)是溢出位,它被丢弃了,这意味着 \(15 + 1\) 看起来等于 0。

二进制乘法

二进制乘法使用简单的移位和加法,类似于十进制的长乘法,但我们只需要乘以 0 或 1。

示例:\(101_2 \times 11_2\) (\(5 \times 3\))

      1 0 1
    x 0 1 1
    -------
      1 0 1 (101 x 1)
+  1 0 1 0 (101 x 1 左移一位)
    -------
   1 1 1 1  (15)

结果:\(1111_2 = 15_{10}\)

🛑 常见错误警示 (算术)

请务必记住二进制加法中的进位!如果你是在固定的位数内工作(如 8 位),任何超出最后一位的进位都是溢出

4.3 使用补码 (Two's Complement) 表示有符号二进制 (3.5.3.3)

为了表示负数,我们使用有符号二进制 (Signed binary)。在本大纲中,你需要掌握的唯一方法是补码 (Two's Complement)

在补码中,最高有效位 (MSB)(最左边的位)作为符号指示符:

  • 如果 MSB 是 0,数字为正。
  • 如果 MSB 是 1,数字为负。
将正十进制转换为补码

这与转换为无符号二进制相同,但如果你是在特定的位数长度内(例如 8 位)工作,则必须确保有一个前导零。

示例: +13 在 8 位中表示为 \(00001101_2\)。

将负十进制转换为补码

遵循“取反加一” (Flip and Add 1) 方法:

  1. 找到该数字的正二进制表示(例如,对于 -13,使用 +13)。
  2. 取反 (Flip) 所有位(0 变成 1,1 变成 0)。这就是反码 (One's Complement)
  3. 将结果加 1

步骤示例:将 \(-13_{10}\) 转换为 8 位补码。

  1. 正 13:\(00001101\)
  2. 位取反(反码):\(11110010\)
  3. 加 1:
        11110010
    +          1
        --------
        11110011
            

结果:\(-13_{10} = 11110011_2\)。 (注意 MSB 是 1,确认它是负数)。

将补码转换回十进制

如果 MSB 是 0,像往常一样转换(它是正数)。

如果 MSB 是 1(它是负数),你可以使用这个快捷方法:将 MSB 视为负权重,并正常求和其余部分。

示例:将 \(11110011_2\) 转换回十进制 (8 位)。

$-2^7 (-128)$$2^6 (64)$$2^5 (32)$$2^4 (16)$$2^3 (8)$$2^2 (4)$$2^1 (2)$$2^0 (1)$
11110011

$$(-128) + 64 + 32 + 16 + 0 + 0 + 2 + 1 = -13$$

补码减法

在计算机算术中,减法 (A - B) 是通过加上 B 的负数来完成的:$$A - B = A + (-B)$$

步骤示例:在 8 位中进行 \(25_{10} - 10_{10}\)。

我们要执行的是 \(25 + (-10)\)。

  1. 正 25:\(00011001\)
  2. 负 10 (\(-10_{10}\)):
    • 正 10:00001010
    • 取反:11110101
    • 加 1:11110110
  3. 将两个二进制数相加:
      1 1 1 1 1 0 0 0 <-- 进位
        0 0 0 1 1 0 0 1  (25)
    +   1 1 1 1 0 1 1 0  (-10)
    ------------------
    (1) 0 0 0 0 1 1 1 1  (15)
            

最后的进位(括号中的)在补码算术中被丢弃。剩下的 8 位 \(00001111_2\),转换为 \(15_{10}\)。

结果:减法通过加法成功完成。

补码的 \(n\) 位范围

由于其中一位专门用于符号位,所以最大范围比无符号二进制要小。

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

$$\text{最小值:} -2^{n-1}$$ $$\text{最大值:} +2^{n-1} - 1$$

示例: 对于 8 位 (\(n=8\)):

  • 最小值:$-2^{(8-1)} = -2^7 = -128$
  • 最大值:$2^{(8-1)} - 1 = 2^7 - 1 = 127$

关键总结:二进制表示

选择无符号还是有符号(补码)决定了你可以存储的数字范围。无符号为你提供了最大的正数范围(例如 8 位中的 0 到 255),而补码允许你存储正整数和负整数(例如 8 位中的 -128 到 127)。