3. 数据表示与运算基础:数制转换、定点数、浮点数(IEEE 754)、字符编码、校验码
计算机体系结构的底层逻辑始于数据的物理表示。无论上层应用多么复杂,最终都要归结为晶体管电平的“0”与“1”。本章将系统讲解数据在计算机内部的表示方法,涵盖数制转换、定点数与浮点数(IEEE 754标准)、字符编码以及校验码。理解这些基础,是后续学习指令系统、运算器设计和存储体系的前提。我们将从数学原理出发,结合工程实践中的典型问题,帮助您建立完整的数据表示知识框架。
3.1 数制转换:从二进制到十六进制
核心原理:计算机内部采用二进制,因为二值逻辑电路最容易实现且抗干扰能力强。但二进制书写冗长,因此工程中常用八进制和十六进制作为二进制的紧凑表示。任何进制数都遵循“按权展开”的数学原理:一个R进制数各位数字乘以对应权值(R的幂次)之和即为十进制值。
转换方法:
- R进制→十进制:按权展开求和。例如二进制
1011.101= 1×2³ + 0×2² + 1×2¹ + 1×2⁰ + 1×2⁻¹ + 0×2⁻² + 1×2⁻³ = 11.625。 - 十进制→R进制(整数部分):除基取余法,将十进制整数不断除以R,取余数逆序排列。例如十进制25转二进制:25÷2=12余1,12÷2=6余0,6÷2=3余0,3÷2=1余1,1÷2=0余1,逆序得11001。
- 十进制→R进制(小数部分):乘基取整法,将小数部分不断乘以R,取整数位正序排列。例如0.625转二进制:0.625×2=1.25取1,0.25×2=0.5取0,0.5×2=1.0取1,得0.101。
- 二进制↔十六进制:每4位二进制对应1位十六进制,以小数点为界分别向两侧分组,不足补0。例如二进制
10110110.1011→ 分组为1011 0110 . 1011 → B6.B。
| 进制 | 基数 | 数字范围 | 典型用途 | 示例 |
|---|---|---|---|---|
| 二进制 | 2 | 0~1 | 机器内部表示 | 1010₂ |
| 八进制 | 8 | 0~7 | Unix文件权限 | 12₈ |
| 十进制 | 10 | 0~9 | 人类日常使用 | 10₁₀ |
| 十六进制 | 16 | 0~9, A~F | 内存地址、颜色值 | 0xFF |
3.2 定点数:原码、反码与补码
核心原理:定点数约定小数点位置固定不变。整数定点数的小数点在最低位之后,纯小数的小数点在符号位之后。为了表示正负数,引入了符号位(通常最高位,0为正,1为负)。三种编码方式各有优劣,其中补码是现代计算机的主流选择。
三种编码的对比:
- 原码:符号位 + 值。直观但存在“+0”和“-0”两种零表示,且加减运算需判断符号,硬件复杂。
- 反码:正数同原码,负数符号位不变、数值位按位取反。解决了部分运算问题,但仍有双零问题。
- 补码:正数同原码,负数在反码基础上加1。消除了双零,使得减法可以统一为加法运算(利用模运算性质),极大简化了ALU设计。
补码的运算优势:对于n位补码,其表示范围为[-2ⁿ⁻¹, 2ⁿ⁻¹-1]。例如8位补码范围为-128~127。计算7-5时,可转换为7+(-5)的补码加法:00000111 + 11111011 = 100000010,丢弃最高位进位得00000010,即2。这种“丢弃进位”正是模2⁸运算的体现。
| 编码方式 | +7 (8位) | -7 (8位) | 零的表示 | 运算复杂度 |
|---|---|---|---|---|
| 原码 | 00000111 | 10000111 | 00000000 / 10000000 | 需判断符号,复杂 |
| 反码 | 00000111 | 11111000 | 00000000 / 11111111 | 需循环进位 |
| 补码 | 00000111 | 11111001 | 唯一:00000000 | 统一加法,简单 |
char类型默认是signed char(8位补码)。当执行char c = 127; c = c + 1;时,结果变为-128。这是因为127的补码01111111加1得到10000000,即-128。理解补码溢出规则对排查此类bug至关重要。
3.3 浮点数:IEEE 754标准
核心原理:浮点数采用科学计数法表示实数,格式为:(-1)^S × 1.M × 2^(E-Bias)。IEEE 754标准定义了单精度(float,32位)和双精度(double,64位)格式。单精度由1位符号位S、8位阶码E(偏移量127)和23位尾数M组成;双精度由1位S、11位E(偏移量1023)和52位M组成。
关键设计点:
- 规格化:尾数最高位隐含为1(即1.M),不显式存储,从而多获得1位精度。
- 阶码偏移:阶码采用无符号整数存储,实际指数 = E - Bias。这样便于比较大小(可直接按无符号整数比较阶码)。
- 特殊值:阶码全0且尾数全0表示±0;阶码全1且尾数全0表示±∞;阶码全1且尾数非0表示NaN(非数值)。
转换流程(以单精度为例):
- 将十进制数转换为二进制科学计数法,如 -12.5₁₀ = -1100.1₂ = -1.1001₂ × 2³。
- 确定符号位S = 1(负数)。
- 计算阶码E = 3 + 127 = 130 = 10000010₂。
- 尾数M = 10010000000000000000000(去掉隐含的1,右侧补0至23位)。
- 组合结果:1 10000010 10010000000000000000000。
0.1 + 0.2 ≠ 0.3(结果为0.30000000000000004)。在金融计算中应使用定点数或十进制浮点库,避免精度损失。
3.4 字符编码:从ASCII到Unicode
核心原理:字符编码将人类可读的字符映射为计算机可处理的二进制数。ASCII(美国信息交换标准码)使用7位编码,共128个字符,包含控制字符、数字、大小写字母和常用符号。由于计算机基本单位是字节(8位),ASCII通常存储为1字节,最高位为0。
Unicode与UTF-8:Unicode为全球所有字符分配唯一码点(如“中”的码点为U+4E2D),但未规定存储方式。UTF-8是一种变长编码,根据码点大小使用1~4字节存储,且兼容ASCII(ASCII字符的UTF-8编码与ASCII完全相同)。UTF-8的编码规则如下:
| 码点范围(十六进制) | UTF-8字节序列 | 字节数 |
|---|---|---|
| 000000 ~ 00007F | 0xxxxxxx | 1 |
| 000080 ~ 0007FF | 110xxxxx 10xxxxxx | 2 |
| 000800 ~ 00FFFF | 1110xxxx 10xxxxxx 10xxxxxx | 3 |
| 010000 ~ 10FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx | 4 |
1110xxxx 10xxxxxx 10xxxxxx中:0100填入第一字节低4位得11100100,111000填入第二字节低6位得10111000,101101填入第三字节低6位得10101101。最终UTF-8编码为E4 B8 AD(十六进制)。在文本编辑器中查看UTF-8编码的“中”字,会看到这三个字节。
3.5 校验码:保障数据完整性
核心原理:数据在传输或存储过程中可能发生位翻转(0变1或1变0)。校验码通过在原始数据后附加冗余信息,使接收方能够检测甚至纠正错误。最基础的校验方式是奇偶校验:统计数据中1的个数,奇校验使总1的个数为奇数,偶校验使总1的个数为偶数。
三种常用校验码对比:
- 奇偶校验:1位冗余,只能检测奇数个错误,无法纠错。适用于低噪声环境。
- CRC(循环冗余校验):将数据视为多项式,用生成多项式做模2除法,余数作为校验码。能检测突发错误,广泛应用于网络帧(如以太网CRC-32)。
- 海明码:在数据位之间插入多个校验位,不仅能检测错误,还能定位并纠正单比特错误。适用于内存ECC(纠错码)等场景。
海明码的构造方法:
- 确定校验位数量r,满足2ʳ ≥ m + r + 1(m为数据位数量)。
- 校验位放在2的幂次位置(1, 2, 4, 8...)。
- 每个校验位负责校验特定位置的位(该校验位索引的二进制位为1的位置)。
- 接收方重新计算校验位,若结果非0,则该值即为出错位置。
总结复盘:本章内容环环相扣——数制转换是理解一切编码的基础;定点数补码解决了有符号整数运算的硬件实现问题;IEEE 754浮点数在精度与范围之间取得平衡,但需警惕舍入误差;字符编码从ASCII到UTF-8的演进体现了兼容性与扩展性的权衡;校验码则为数据可靠性提供了保障。在实际系统设计中,这些知识往往综合运用:例如网络协议栈中,IP头校验和(补码求和)、TCP段CRC校验、应用层UTF-8编码,共同构成了完整的数据处理链路。建议读者通过编写进制转换工具、模拟浮点数舍入、实现CRC校验算法等方式加深理解。