第三章 数据表示与编码:进制转换、原码、反码、补码、移码与定点数表示范围
计算机系统中最底层的语言是二进制,但人类习惯使用十进制。如何在这两种进制之间建立精确、高效的映射,是计算机组成原理的基石。本章将系统讲解进制转换的通用方法,深入剖析原码、反码、补码、移码四种机器数编码的定义、转换规则与适用场景,并重点推导定点数(含纯小数与纯整数)的表示范围。理解这些内容,是后续学习定点运算、浮点数标准(IEEE 754)以及ALU设计的前提。
3.1 进制转换:从十进制到二进制的通用方法
核心原理:位权展开与基数除法
任何进制数的本质是“位权”的线性组合。十进制数 \(D = \sum_{i=-m}^{n-1} d_i \times 10^i\),二进制数 \(B = \sum_{i=-m}^{n-1} b_i \times 2^i\)。进制转换的核心就是求解二进制各位系数 \(b_i\)。整数部分采用“除2取余,倒序排列”;小数部分采用“乘2取整,正序排列”。
操作流程:整数与小数分离处理
- 整数部分:将十进制整数反复除以2,记录每次的余数(0或1),直到商为0,将余数从下往上排列。
- 小数部分:将十进制小数反复乘以2,记录每次的整数部分(0或1),直到小数部分为0或达到精度要求,将整数部分从上往下排列。
- 合并:整数结果 + 小数点 + 小数结果。
案例拆解:将十进制数 13.625 转换为二进制。
整数部分 13:13÷2=6 余1,6÷2=3 余0,3÷2=1 余1,1÷2=0 余1 → 倒序得 1101。
小数部分 0.625:0.625×2=1.25 取1,0.25×2=0.5 取0,0.5×2=1.0 取1 → 正序得 101。
最终结果:13.625₁₀ = 1101.101₂。
整数部分 13:13÷2=6 余1,6÷2=3 余0,3÷2=1 余1,1÷2=0 余1 → 倒序得 1101。
小数部分 0.625:0.625×2=1.25 取1,0.25×2=0.5 取0,0.5×2=1.0 取1 → 正序得 101。
最终结果:13.625₁₀ = 1101.101₂。
常见误区
- 小数精度陷阱:十进制小数不一定能精确转换为有限位二进制小数(如0.1₁₀ = 0.000110011...₂循环),需根据精度要求截断。
- 顺序混淆:整数部分余数要倒序,小数部分整数位要正序,两者方向相反,极易出错。
- 八进制/十六进制捷径:二进制与八进制(3位一组)、十六进制(4位一组)之间可直接分组转换,无需经过十进制中转。
3.2 四种机器数编码:定义与转换
核心原理:符号数值化与模运算
计算机无法直接存储“+”和“-”符号,必须将符号编码为0(正)和1(负)。原码最直观,但加减法运算复杂;补码通过“模”的概念将减法转化为加法,使得符号位可以参与运算,从而简化硬件设计。移码则是在补码基础上将符号位取反,用于浮点数阶码的比较。
| 编码类型 | 正数表示 | 负数表示 | 零的表示 | 主要用途 |
|---|---|---|---|---|
| 原码 | 符号位0 + 值 | 符号位1 + 值 | +0:0000;-0:1000 | 乘除法、浮点数尾数 |
| 反码 | 同原码 | 原码按位取反(符号位不变) | +0:0000;-0:1111 | 补码的中间过渡 |
| 补码 | 同原码 | 反码 + 1 | 唯一:0000 | 整数加减法运算 |
| 移码 | 补码符号位取反 | 补码符号位取反 | 唯一:1000 | 浮点数阶码、比较大小 |
转换规则与速算技巧
- 原码 → 反码:正数不变;负数符号位保持1,数值位逐位取反。
- 反码 → 补码:正数不变;负数在反码基础上末位加1。
- 补码 → 原码:正数不变;负数对补码再次求补(取反加1)即得原码。
- 补码 → 移码:符号位直接取反,数值位不变。
- 速算口诀:补码负数 = 从右往左找到第一个1,该位左边所有位取反(符号位不变)。
实战场景:以8位机器数为例,求 -5 的四种编码。
5 的二进制为 0000 0101。
原码:1000 0101(符号位1,数值位101)
反码:1111 1010(符号位不变,数值位取反)
补码:1111 1011(反码+1)
移码:0111 1011(补码符号位取反)
验证:补码 1111 1011 转回十进制,先取反加1得 0000 0101 = 5,加上负号即 -5。
5 的二进制为 0000 0101。
原码:1000 0101(符号位1,数值位101)
反码:1111 1010(符号位不变,数值位取反)
补码:1111 1011(反码+1)
移码:0111 1011(补码符号位取反)
验证:补码 1111 1011 转回十进制,先取反加1得 0000 0101 = 5,加上负号即 -5。
常见误区
- 补码的“+1”位置:反码加1是对整个反码数值位加1,若产生进位会向符号位传递,但符号位不参与运算。
- 零的唯一性:原码和反码都有“+0”和“-0”两种表示,而补码和移码的零是唯一的,这是补码能多表示一个最小负数(-2ⁿ⁻¹)的原因。
- 移码与补码的关系:移码不是独立编码,它只是补码的符号位取反,目的是让所有数值的大小顺序与无符号数一致,便于硬件比较。
3.3 定点数的表示范围
核心原理:定点数的格式约定
定点数约定小数点位置固定不变。常见两种格式:定点纯小数(小数点固定在符号位之后)和定点纯整数(小数点固定在最低位之后)。n位定点数包含1位符号位和(n-1)位数值位。
表示范围推导
| 格式 | 编码类型 | 最小值 | 最大值 | 说明 |
|---|---|---|---|---|
| 定点纯小数 (n位含符号) |
原码/反码 | -(1-2⁻⁽ⁿ⁻¹⁾) | +(1-2⁻⁽ⁿ⁻¹⁾) | 关于原点对称,有±0 |
| 补码 | -1 | +(1-2⁻⁽ⁿ⁻¹⁾) | 最小负数可到-1(1000...0) | |
| 定点纯整数 (n位含符号) |
原码/反码 | -(2ⁿ⁻¹-1) | +(2ⁿ⁻¹-1) | 关于原点对称,有±0 |
| 补码 | -2ⁿ⁻¹ | +(2ⁿ⁻¹-1) | 最小负数多一个-2ⁿ⁻¹ |
关键推导:以8位补码定点整数为例,最大正数为 0111 1111 = 127 = 2⁷-1;最小负数为 1000 0000 = -128 = -2⁷。补码的1000 0000没有对应的原码和反码,它被约定为-128。因此8位补码整数范围是 [-128, 127],而原码/反码范围是 [-127, 127]。
实战场景:溢出判断
在定点数运算中,结果超出表示范围即发生溢出。例如8位补码整数运算:120 + 20 = 140,但140 > 127,结果溢出。硬件上可通过“双符号位”或“最高位进位与符号位进位异或”来判断溢出。
风险提示:溢出与进位是两个不同概念。进位是最高位产生的进位,溢出是结果超出表示范围。例如 1000 0000 + 1000 0000 = 1 0000 0000,有进位但结果 -128 + (-128) = -256 溢出;而 1111 1111 + 0000 0001 = 1 0000 0000,有进位但结果 -1 + 1 = 0 未溢出。判断溢出必须看符号位变化,不能只看进位。
总结复盘
- 原码:人类最易理解,但运算电路复杂,不适合加减法。
- 补码:现代计算机整数运算的标准编码,统一了加减法,零唯一。
- 移码:专为浮点数阶码设计,便于比较大小。
- 定点数范围:补码比原码/反码多表示一个最小负数,这是模运算带来的“红利”。
掌握这四种编码的转换与定点数范围,是后续学习ALU设计、浮点数IEEE 754标准以及数据校验(如CRC)的基础。建议读者反复练习8位和16位机器数的编码转换,并尝试用程序验证结果。