第3章信息的表示
在表示数据或者与计算机通信时,用户要依靠符号——数字、字母和标点符号,它们一起构成了字符串(CharacterString)。
例如,下面的代码行:
1i=15;r=1.5;
2car1="15";car2="Hello";
3DIR>Result.doc
4catResult.tex
被解释为程序的指令(第1、2行)或者发送给操作系统的命令(第3、4行)。这种数据的外部表示(ExternalRepresentation)不能直接被机器所理解。它需要翻译(编码(Code))成计算机可以使用的格式。我们将这种操作的结果称为内部表示(InternalRepresentation)。它涉及使用通过0和1表示的逻辑符号的各种情况(参见3.2.2节)。出于清晰和/或简化规范的原因,通常把逻辑(Logical)数据划分成8个元素的组,称为字节(Byte)。
在本章中,将区分以下类型:数字、整数或实数和字符。
再次考虑前面的示例:依赖于数据是存储在变量i还是变量car1中,数据“15”的内部编码将是不同的。一种是数值(Numerical),另一种是字符串(CharacterString)。对于两个实体来说,其外部表示是相同的,尽管事实上它们本质上根本不同。人类操作员能够区分它们,并且可以根据环境或者使用他们所了解的关于对象的知识来采纳他们的处理方式。另一方面,对于不同类型的对象,机器需要不同的内部表示。在本章中,将介绍使得有可能把外部格式(ExternalFormat)转换成内部格式(InternalFormat)的规则,而无须假定结果在机器的存储器中最终是如何植入的。
3.1复??习
3.1.1以2为基数
以b为基数的数字x的表示(Representation)被定义为矢量{an,…,a0,a–1,…,a–p},满足:
其中,ai是0~b–1之间的整数。索引i和数bi分别是符号ai的位置(Position)和加权(Weight)。系数an和a?p分别是最高有效位(MostSignificantDigit)和最低有效位(LeastSignificantDigit)。对于基数2(二进制编码(BinaryCoding))来说,系数ai可能假定为值0或1,并将被称为位(Bit),它是二进制数位(BinaryDigit)的简写形式。
示例3.1:
二进制数1010=1×23+0×22+1×21+0=1010。
从十进制转换成二进制的整数部分是通过2的除法系列(SeriesOfDivisions)完成的,而小数部分则是通过2的乘法系列(SeriesOfMultiplications)完成的。考虑十进制数20.375。
可以通过执行以下操作将其转换为二进制表示。
(1)对于整数部分xINT,执行除法系列:
202
0102
052
122
01
结果是通过最后的商和前面的余数给出的,得到xINT=101002。
(2)小数部分xFRAC是通过2的乘法系列获得的,因此,对于0.375:
0.375×2=0.75
??????????????0.75×2=1.5
??????????????0.5×2=1
小数部分的数字是通过乘以2的结果的整数部分给出的。这里,得到xFRAC=0.0112。最后,20.37510=xINT+xFRAC=10100.0112。注意:二进制表示不一定是有限的,即使十进制表示是这样的。因此,0.210将变成0.001100110011…。小数部分的位数是无限的。
通过限制表示的位数而引入的误差称为截断误差(TruncationError)。在这种表示中被舍入的误差称为化整误差(RoundingError)。
例如,通过截断,得到0.210≈0.0011001100;通过化整,得到0.210≈0.0011001101。
3.1.2二进制、八进制和十六进制表示
在我们特别感兴趣的二进制中,无论数据是否是数字,用于数据表示的两种逻辑状态使用符号0和1表现。出于实际的原因,外部表示通常使用基数8(八进制(Octal)Representation)或基数16(十六进制(Hexadecimal)Representation)。
八进制系统使用8个符号:0、1、2、3、4、5、6和7。从基数2转换为基数8(=23)是通过“从小数点开始”,将二进制数位三位一组地进行划分即时完成的。例如:
1011101.011012=1|011|101.011|010=135.328
基数16使用符号0、1、2、3、4、5、6、7、8、9、A、B、C、D、E和F。从基数2转换为基数16(=24)是以相同的方式完成的,即“从小数点开始”,将二进制数位4位一组地进行划分。例如:
1011101.011012=101|1101.0110|10=5D.6816
这些基数不仅提供了二进制数位的精简表示,而且使得有可能即时转换成基数2。
3.2数字表示约定
数值的表示需要使用一些规则,它们有利于硬件和软件处理。我们将不会提及所有现有的约定,因此这里将只讨论最常见的约定。
3.2.1整数
1.经典表示:符号和绝对值
在第一种约定中,表示将使用符号位(0→+、1→?)以及用二进制编码的数的绝对值。表3.1给出了利用这种约定的16位的表示。
表3.1符号和绝对值表示
十进制值符号/绝对值十六进制表示
+20/0000000000000100002
+00/0000000000000000000
–01/0000000000000008000
–31/0000000000000118003
在这种表示中,有+0和?0。对于设计用于处理以这种方式编码的数字上的操作的电路,将具有比那些用于处理以2的补码(Two’sComplement)编码的数字的电路更高的复杂性。
2.1的补码表示
负数及其绝对值x是用n位编码的,使得x+=2n–1(“逐位”求补)。注意:可以通过00…0和11…1表示“0”。
3.2的补码表示
这种表示没有上面提到的缺点。负数的2的补码编码是通过获取其绝对值相对于2n的补码完成的,其中,n是用于编码的位数。数及其补码的二进制求和的结果是n以及一个进位1。如果把定义为A的2的补码,则有:
A+=2n
表3.2显示了几个十进制数及其使用16个二进制数位表示的二进制数之间的对应关系。
表3.22的补码表示
十进制值二进制编码十进制值二进制编码
20000000000000010?11111111111111111
10000000000000001?21111111111111110
00000000000000000
从一个正数转换成一个具有相同绝对值的负整数,或者执行相反的操作,是通过对数字逐位求补,然后把求补的结果加1完成的。
这是因为,根据定义:
=2n?A=(2n?1)??A+1
而((2n?1)??A)是通过对A逐位求补得到的。
示例3.2:要获得整数?1010的16位的2的补码表示,首先从1010的二进制表示开始,即00000000000010102,然后对其求补:
(216?1)??10==1111111111110101
然后将其加1,得到:
11111111111101102,即FFF616或1777668
常见的编程语言使用16、32或64位的2的补码表示整数。可以轻松确认:在16位的表示中,任何整数N都满足:
?3276810≤N≤3276710
4.二进制编码的十进制
在某些情况下,我们不使用二进制表示,而更喜欢使用另外某种编码方式,它使得更容易从十进制编码转换成机器表示。常用的代码称为二进制编码的十进制(Binary-Coded-Decimal,BCD)。
对于以十进制表示的数的每个数位,都使用4位进行编码。这种表示或者其他共享相同概念的表示通常使用在用于管理的语言(如COBOL)中。尽管BCD编码在操作期间的内部过程比使用2的补码约定的数字更复杂(由于硬件计算单元通常操作的是2的补码表示),但它在管理中展示了一个重要的优点:当从十进制转换成内部表示时,将不会有截断误差(TruncationError)(参见3.2.2节)。
符号是单独编码的,将给其分配一个半字节,它所具有的值不同于用于数位的代码。
有几种BCD代码:BCD-8421或BCD、Excess-3BCD(XS-3,0被编码为0011,1被编码为0100等)以及BCD-2421(0~4的编码方式与BCD中相同,5~9则是从1011~1111编码的)。最后两个代码是对称的,“逐位”求补则导致了对应十进制表示的9的补码。在BCD“Comp-3”表示中(IBM的打包十进制(PackedDecimal)表示),+符号被编码为C(1100),–符号则被编码为D(1101)。
示例3.3:整数–1289被表示为:
3.2.2实数
有两种表示实数的方法:定点(Fixed-Point)表示和浮点(Floating-Point)表示。
1.定点表示
定点表示通常用在机器只用于处理整数以及计算速度至关重要的领域(例如,在信号处理中)。即使有诱惑力,但是其中包含以“科学”或“浮点”格式编码数字的解决方案将导致处理时间和能耗显著增加。
“定点”表示将小数点任意放置在二进制表示的两个数位之间。其中的k位被分配给小数部分的表示被称为Qk表示法。显然,必须先分析使用的值的动态性,以避免可能被处理导致的任何饱和度。
示例3.4:可以使用以下方式在Q8中以N=16位编码数5.75:
00000101.11000000
其中,点是象征性地表示的,以指示编码。
对应的整数是通过对实数乘以2k的结果进行四舍五入获得的。利用这种约定(k=8),数?5.75将编码为:
?5.75×28=?147210=FA4016=11111010.01000000
从操作的角度讲,两个Qk数的和是Qk,而它们的乘积是Q2k。另请注意,重要的数字会出现在结果的最高有效位一端,而不会出现在最低有效位一端!这解释了在某些处理器中存在乘法移位(Multiplication-Shift)运算符,在执行乘法运算后具有一个Qk。
示例3.5:考虑Q3定点中以4位编码的数。我们将执行“带符号”的乘法。获取结果需要右移三位。有三种可能的情况,现在将介绍它们。
(1)首先,设两个数均为正:
(2)利用相同的编码规则,现在考虑两个具有相反符号的数:
(3)利用相同的编码规则,对于两个负数:
在实际中,使用的主要格式是Q15,它需要对处理的数进行移位,使得它们的模数小于0.5。
在这类编码中,管理小数点的位置就作为一项任务留给程序员完成,他们必须增加表示的位数,以维持相同的精度。要执行P个加法,必须向表示中添加log?2P个位。乘法提出了一个更困难的挑战。以N位编码的两个数的乘积的结果将通过2N位表示。执行一系列的截断可能导致灾难性的结果。
2.浮点表示
在几种常见的高级编程语言中,当以下面任何一种格式声明变量x时,就使用这种表示。
floatx;inCorJava
singlex;inBasic
x;Float;inAda