第2章 数制与编码(信息的表示)
一、导读
1.1 本章学习目标
熟练掌握二进制、八进制、十六进制的表示方法及其相互转换
理解有符号数的多种表示方法:原码、反码和补码
掌握二进制算术运算规则,特别是补码加减法的原理
了解BCD码、Gray码、ASCII码等常见编码方式及其应用
理解奇偶校验码和汉明码的基本原理
掌握定点数和浮点数的表示方法及其精度差异
能够根据具体应用场景选择最合适的数制和编码方案
1.2 为什么本章如此重要
数制与编码是数字设计的语言基础。就像学习一门新语言必须先掌握其字母表和语法规则一样,学习数字设计必须首先精通各种数制系统和编码方式。在数字系统中,每一个电压的高低、每一个信号的有无,都被抽象为"0"和"1"这两个基本符号。如何有效地组织、表示和运算这些二进制信息,是整个数字设计的根基。
二进制系统之所以成为数字系统的基础,有着深刻的物理和数学原因。从物理层面看,电子器件最容易稳定地区分两种状态——导通与截止、高电平与低电平、有电流与无电流。二进制恰好只需要两个符号,与电子器件的这种双稳态特性完美匹配。从数学层面看,二进制运算规则极其简单,加法只有四条基本规则(0+0=0, 0+1=1, 1+0=1, 1+1=10),这使得硬件实现变得非常简洁可靠。
补码表示法的引入是数字算术设计中最精妙的创造之一。补码系统巧妙地将减法运算转化为加法运算,使得CPU只需要一套加法电路就能处理加减两种运算,极大地简化了硬件设计。理解补码的原理不仅是理论学习的需要,更是排查实际工程中整数溢出、符号扩展等问题的必备技能。
编码方式的选择直接影响系统的性能和可靠性。不同的编码方案在信息密度、运算便利性、错误检测能力和抗干扰性能等方面各有优劣。在后续的电路设计和系统开发中,你将频繁地与各种编码打交道——地址总线使用二进制编码,七段显示器需要BCD到七段码的转换,通信协议中需要校验码来保证数据的完整性。
1.3 核心问题引导
为什么数字系统选择二进制而不是十进制作为基础数制?
补码表示法相比原码有什么优势?为什么现代计算机统一使用补码?
如何将一个十进制小数转换为二进制表示?为什么有些十进制小数无法用有限位二进制精确表示?
Gray码有什么特殊性质?它在实际工程中有哪些重要应用?
为什么需要校验码?奇偶校验和汉明码各自的检错纠错能力如何?
浮点数表示法是如何在有限的位数内同时表示极大和极小数值的?
在实际电路设计中,什么时候使用BCD码比纯二进制更合适?
二、核心概念详解
2.1 二进制与进制转换
二进制(Binary)是数字系统的基础数制,仅使用0和1两个符号。每个二进制位(bit)代表一个2的幂次。一个n位二进制数b_{n-1}b_{n-2}...b_1b_0的十进制值为各位与其权值乘积之和。例如,二进制数1101_2 = 1x2^3 + 1x2^2 + 0x2^1 + 1x2^0 = 8 + 4 + 0 + 1 = 13。
八进制(Octal)使用0至7共八个符号,每个八进制位对应三个二进制位。这种对应关系使得二进制与八进制之间的转换极为简便:只需将二进制数从右向左每三位分为一组,然后将每组转换为对应的八进制数字即可。例如,二进制数11010110可以分为11_010_110三组,对应八进制数326。
十六进制(Hexadecimal)使用0至9和A至F共十六个符号,每个十六进制位对应四个二进制位。十六进制在数字系统中使用极为广泛,因为一个字节(8位)恰好可以用两个十六进制数字表示。例如,二进制数10110100对应十六进制数B4。在嵌入式系统和数字电路设计中,十六进制是最常用的数的表示方式。
十进制到二进制的转换采用除基取余法:将十进制数反复除以2,记录每次的余数,直到商为0,然后将余数从下往上排列。对于十进制小数部分,则采用乘基取整法:将小数部分反复乘以2,记录每次的整数部分,直到小数部分为0或达到所需精度。
2.2 有符号数与补码
在数字系统中表示有符号数(正数和负数)需要特殊的方法。最直观的是原码(Sign-Magnitude)表示法:最高位作为符号位(0表示正,1表示负),其余位表示数值的绝对值。例如,8位原码中,+5表示为00000101,-5表示为10000101。原码的问题在于零有两种表示(+0和-0),且加减法电路设计复杂。
反码(Ones Complement)是对原码的改进:正数的反码与原码相同,负数的反码是将原码的数值位逐位取反。反码同样存在零的双重表示问题(00000000和11111111都表示零)。
补码(Twos Complement)是解决上述问题的最终方案。正数的补码与原码相同;负数的补码是在反码的基础上加1。在8位补码系统中,数值范围为-128至+127。补码的核心优势在于:零只有唯一表示(00000000);减法可以转化为加法(A - B = A + (-B)的补码);加法电路不需要区分正负数,统一使用同一套运算逻辑。
补码加法遵循模运算规则。当两个8位补码数相加时,如果结果超出表示范围(-128至+127),则发生溢出。溢出的判断规则是:两个正数相加结果为负,或两个负数相加结果为正,则发生了溢出。
2.3 BCD码与字符编码
BCD码(Binary-Coded Decimal)是一种特殊的编码方式,用四位二进制数表示一位十进制数字。例如,十进制数259的BCD码为0010_0101_1001,而其二进制表示为100000011。BCD码的优势在于十进制数字与编码之间有直观的对应关系,便于显示和输入输出转换。但其缺点是存储效率较低(四位二进制可以表示0至15,但BCD码只用到了0至9),且算术运算需要额外的校正电路。
ASCII码(American Standard Code for Information Interchange)是最基本的字符编码标准,使用7位二进制数表示128个字符,包括大小写英文字母、数字字符、标点符号和控制字符。扩展ASCII码使用8位,可以表示256个字符。在现代系统中,Unicode编码(特别是UTF-8格式)已经取代ASCII成为主流,但ASCII码作为Unicode的子集仍然是最基础的编码知识。
Gray码(格雷码)是一种特殊的编码方式,其特点是相邻两个编码之间只有一位不同。这种"单位距离"特性使得Gray码在需要避免多位同时变化的场合非常有用。例如,在旋转编码器中,使用Gray码可以确保在位置变化时只有一位输出发生改变,避免了多位同时跳变可能导致的读取错误。典型的3位Gray码序列为:000, 001, 011, 010, 110, 111, 101, 100。
2.4 校验码与错误检测
在数据传输和存储过程中,噪声和干扰可能导致数据位发生翻转。校验码(Check Code)是一种通过在数据中添加冗余位来检测甚至纠正错误的技术。
奇偶校验(Parity Check)是最简单的校验方式。偶校验在数据位后添加一个校验位,使得整个码字中1的个数为偶数;奇校验则使1的个数为奇数。奇偶校验可以检测单个位的错误,但无法纠正错误,也无法检测偶数个位同时出错的情况。
汉明码(Hamming Code)是一种更强大的纠错码。通过在数据位中插入多个校验位,汉明码不仅可以检测错误,还能定位并纠正单个位的错误。汉明码的校验位数量k与数据位数量n之间的关系为2^k >= n + k + 1。例如,4位数据需要3个校验位,形成7位汉明码。汉明码在内存系统(ECC内存)、通信系统和存储系统中有着广泛的应用。
2.5 浮点数表示
浮点数表示法(Floating-Point Representation)允许在有限的位数内表示极大和极小的数值。IEEE 754标准定义了单精度(32位)和双精度(64位)浮点数的格式。单精度浮点数由1位符号位、8位指数位和23位尾数位组成,可以表示约7位有效十进制数字。双精度浮点数由1位符号位、11位指数位和52位尾数位组成,可以表示约15位有效十进制数字。
浮点数的核心思想是将一个数表示为尾数乘以基数的指数次幂。这种表示方法牺牲了绝对精度来换取表示范围。浮点数在表示非常大或非常小的数时非常有效,但在需要精确表示十进制小数的场合(如金融计算)可能引入舍入误差。
三、深入分析与讨论
3.1 补码运算的数学本质
补码系统的数学基础是模运算(Modular Arithmetic)。在n位二进制系统中,运算的模为2^n。补码表示本质上是将负数映射到模空间中的正数等价类。例如,在8位系统中(模为256),-1的补码表示为255(即11111111),因为在模256的运算中,255和-1是等价的:任何数加上255再对256取模,等于该数减去1。
这种映射的巧妙之处在于,它将减法运算统一为加法运算。计算A - B时,只需计算A + (B的补码),然后丢弃超出n位的进位。硬件上只需要一个加法器,无需额外的减法器电路。这不仅节省了芯片面积,还简化了控制逻辑。
3.2 编码方案的工程选择
在实际工程中,编码方案的选择需要综合考虑多种因素。对于需要频繁进行算术运算的数据,纯二进制或补码是最佳选择,因为硬件运算电路最为简单高效。对于需要直接驱动十进制显示的场合,BCD码可以避免二进制到十进制的转换开销。对于位置检测和角度测量,Gray码可以消除多位同时变化带来的不确定性。
在通信系统中,编码方案的选择还需要考虑错误检测和纠正能力。简单的奇偶校验适用于错误率较低的场合,而汉明码、CRC码等更复杂的编码方案则适用于对可靠性要求较高的应用。现代存储系统和通信协议通常采用多层编码策略,在不同层次上使用不同类型的校验码来保证数据的完整性。
四、实践案例
4.1 补码溢出导致的软件Bug
在1996年,欧洲航天局的Ariane 5火箭在发射后37秒爆炸,造成约5亿美元的损失。事故调查的一个重要发现与数据格式转换有关:一个64位浮点数被转换为16位有符号整数时发生了溢出。这个值在Ariane 4的飞行轨迹中不会出现,但Ariane 5的更高加速度导致了更大的数值,超出了16位有符号整数的表示范围(-32768至32767)。
这个案例深刻地说明了数制和编码知识在实际工程中的重要性。在进行数据类型转换时,必须仔细检查数值范围是否超出目标类型的表示能力。补码溢出是数字系统中最常见也最隐蔽的错误之一,它可能在特定输入条件下才会触发,给测试和调试带来很大困难。
4.2 Gray码在旋转编码器中的应用
绝对式旋转编码器用于精确测量旋转角度。编码器盘上有多圈同心码道,每条码道对应一个输出位。如果使用普通二进制编码,在某些角度边界处可能有多位同时发生变化,导致读数出现大幅跳变。例如,从0111(7)到1000(8)有四位同时变化,如果各码道的对齐存在微小偏差,读取结果可能出现短暂的错误值。
使用Gray码可以彻底解决这个问题。由于Gray码相邻编码之间只有一位变化,无论码道对齐精度如何,读取结果最多只有一位的不确定性,对应的角度误差不会超过一个最小分辨率。这种特性使得Gray码在工业控制、机器人关节角度测量和数控机床定位等精密应用中被广泛采用。
五、常见误区与注意事项
误区一:补码就是取反加一,所以负数的补码一定比对应的正数小。 在补码系统中,负数的编码值(作为无符号数看待)实际上大于对应的正数。例如,-1的8位补码是11111111(无符号值为255),远大于+1的编码00000001。补码的大小比较必须考虑符号位。
误区二:BCD码和二进制没有本质区别。 BCD码和纯二进制是完全不同的编码方式。同一个十进制数,其BCD码和二进制编码通常不同。例如,十进制数99的BCD码是1001_1001(8位),而二进制编码是1100011(7位)。BCD码的算术运算需要额外的校正步骤。
误区三:浮点数可以精确表示所有实数。 浮点数在有限位数内只能近似表示大多数实数。例如,十进制的0.1在单精度浮点数中无法精确表示,其实际存储值约为0.100000001490116。在进行浮点数比较时,应使用容差比较而非直接相等比较。
误区四:奇偶校验可以检测所有错误。 奇偶校验只能检测奇数个位同时出错的情况。如果偶数个位同时发生翻转,奇偶校验无法发现错误。在错误率较高的信道中,应使用更强大的校验方案如CRC或汉明码。
六、本章小结
本章全面介绍了数字系统中数制与编码的核心知识。我们掌握了二进制、八进制、十六进制的表示和转换方法,深入理解了补码系统的数学原理和工程优势,学习了BCD码、Gray码、ASCII码等常见编码方式的特点和应用场景。校验码和浮点数表示的知识进一步扩展了我们对信息表示的理解。这些基础知识是数字设计的语言工具,熟练掌握它们将使后续的电路分析、逻辑设计和系统实现变得更加顺畅高效。
七、思考题与练习
将十进制数373转换为二进制、八进制和十六进制表示,验证三种表示之间的对应关系。
写出-43的8位原码、反码和补码表示。验证补码表示下,43 + (-43) = 0。
解释为什么补码系统中-128(10000000)没有对应的正数+128。8位补码系统的数值范围为什么是不对称的?
将十进制数0.6875转换为二进制小数。再将十进制数0.1转换为二进制小数(保留至少10位),说明为什么0.1无法用有限位二进制精确表示。
设计一个将3位Gray码转换为3位二进制码的组合电路,写出真值表和简化的逻辑表达式。
对于8位数据,计算需要多少个校验位才能构成汉明码。写出数据1011的7位汉明码编码过程。
比较BCD码和纯二进制码在表示十进制数0至99时的位数效率。如果需要对两个BCD编码的十进制数进行加法运算,说明校正电路的工作原理。
查阅IEEE 754标准,解释单精度浮点数中指数偏移值(Bias)的作用。为什么单精度浮点数的指数偏移值是127而不是128?