👋 欢迎来到二进制系统!
欢迎来到计算机科学最基础的构建模块!本章“二进制数系统”是你探索数据表示(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 的十进制转换为二进制)
- 找出小于等于42的最大2的幂(是32)。在该位上写1。
- 用42减去32。余数为10。
- 检查下一个2的幂(16)。16能放入10吗?不能。写0。
- 检查8。8能放入10吗?能。写1。余数为2。
- 检查4。4能放入2吗?不能。写0。
- 检查2。能。写1。余数为0。
- 检查1。不能。写0。
4210 = 001010102(8位表示)
二进制转十六进制(快速方法)
- 从右向左将二进制数字每4位分成一组(每4位一组称为一个“半字节”,正好对应一个十六进制数字)。
- 将每组转换成对应的十六进制。
例如: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。
- 找到正数的二进制: +5 的8位二进制是 0000 0101。
-
按位取反(翻转): 将所有的0变为1,所有的1变为0(这称为反码)。
0000 0101 变为 1111 1010。 -
结果加1:
1111 1010 + 1 = 1111 1011。
这就是 -5 的补码表示。(注意 MSB 为 1,表示这是一个负数)。
3.4 使用补码进行减法
补码的神奇之处在于减法 (A - B) 等同于加法 (A + (-B))。
示例:计算 12 - 5(使用8位)
- 表示 12: 0000 1100
- 表示 -5: 1111 1011(来自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}\))。二进制点“浮动”以最大化表示的有效数字。
浮点数由两个主要部分组成,通常都使用补码表示:
- 尾数 (Mantissa, M): 表示数字的有效数字(精度)。
- 指数 (Exponent, E): 表示尾数所乘的2的幂(范围)。
其值计算公式为: \( M \times 2^E \)
4.2.1 范围 vs. 精度
位数在尾数和指数之间的分配方式决定了系统的能力:
- 精度: 由尾数的位数决定。尾数位数越多 = 数字表示越精确(舍入误差越小)。
- 范围: 由指数的位数决定。指数位数越多 = 存储极大或极小数字的能力越强。
4.2.2 规范化 (3.5.3.9)
为了确保每个数字都有唯一的表示并最大化精度,浮点数必须进行规范化(Normalisation)。
为什么规范化? 为了将二进制点固定在一个标准位置,从而消除冗余的零。
规范化规则: 尾数必须以“01...”开头(正数)或“10...”开头(负数)。
如何规范化(步骤):
- 移动二进制点,直到尾数以 01(正)或 10(负)开头。
- 更新指数以反映你移动点的位数。
示例:非规范化的正数 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\))
- 我能使用补码来表示负数并执行减法吗?
- 我理解在浮点数中,尾数控制精度,指数控制范围吗?
- 我能解释什么是规范化以及为什么它很重要吗?
- 我清楚溢出(太大)和下溢(太接近于零)的区别吗?
恭喜!你已经掌握了计算机内部数字管理的核心概念。继续练习那些进位制转换和补码计算步骤吧!