1.3 计算机内信息的表示与编码
二进制数是计算机表示信息的基础。本节首先引入二进制数的概念,然后介绍数值型数据在计算机内的表示方法和字符(包括英文字符和汉字)在计算机内的表示方法。
1.3.1 二进制
人类习惯使用十进制表示数。十进制有10个不同的数字(表记符号),它们是:0、1、2、3、4、5、6、7、8、9。十进制数进行运算时遵循“逢十进一”的规则。在进位计数制中所用的不同数字的个数称为该进位计数制的基数,因此十进制的基数是10。
在人类社会发展过程中,人类还创造了各种不同的进位计数制。例如,一天24小时,即24进制,逢24进1;一小时60分,即60进制,逢60进1;一周7天,即7进制,逢7进1。在上述进位计数制中,有的有自己的标记符号,有的借用其他进位计数制的标记符号。用什么标记符号并不重要,只要使用方便即可。不同进位计数制之间的区别在于它们的基数和标记符号不同,进位规则不同。
1.二进制数
二进制数只有0和1两个记数符,其进位的基数是2,遵循“逢二进一”的进位规则。在计算机中采用二进制数表示数据。原因在于:
(1)计算机科学理论已经证明:计算机中使用e进制(e≈2.718)最合理,取整数,可以使用三进制或二进制。
(2)由于二进制容易实现,在计算机内可用电压的高和低来表达1和0两个数字,如果使用三进制则需要3个电压量来表达其3个标记符号,显然,其可靠性比使用二进制更容易受电压波动的影响。
(3)运算简单:0+0=0,0+1=1,1+0=1,1+1=10;数值量与逻辑量共存,便于用逻辑运算器件实现算术运算。
二进制的基数为2,标记符号只有两个:0和1,运算遵循“逢二进一”的规则。如:
2.八进制与十六进制数
人类使用二进制表达一个比较大的数值时,书写较长,看起来不直观,很容易出错。由于八进制和十六进与二进制有运算上的完全对应关系,所以常常采用八进制和十六进制记数法(便于人们阅读)。
八进制的基数为8,共有8个标记符号:0、1、2、3、4、5、6、7,运算遵循“逢八进一”的规则。1位八进制数正好用3位二进制数表达,它们的对应关系是:
八进制数与二进制数的转换很容易,按照上表,每1位八进制数写成对应的3位二进制数即完成八进制数到二进制数的转换;从低位到高位每3位二进制数写成对应的1位八进制数即完成二进制数到八进制数的转换。如(157)8=(001101111)2。
十六进制的基数为16,共有16个标记符号:0、1、2、3、4、5、6、7、8、9、A、B、C、D、E、F,运算遵循“逢十六进一”的规则。1位十六进制数正好用4位二进制数表达,它们的对应关系是:
十六进制数与二进制数的转换同样很容易,按照上表,每1位十六进制数写成对应的4位二进制数即完成十六进制数到二进制数的转换;从低位到高位每4位二进制数写成对应的1位十六进制数即完成二进制数到十六进制数的转换。如(FD57)16=(1111110101010111)2。
3.二进制数与十进制数的转换
十进制毕竟是人们最熟悉的数制。在计算机的输入/输出中通常采用十进制,即人们使用十进制数输入数据、计算机使用十进制数输出数据,机内数据存储使用二进制。数据的输入/输出过程中的十进制数到二进制数、二进制数到十进制数的转换由机器自动完成。
(1)二进制数→十进制数。一个二进制数按其权位(权位用十进制表示)展开求和,即可得相应的十进制数。如:
(110.101)2=(1×22+1×21+0×20+1×2-1+0×2-2+1×2-3)10
=(4+2+0.5+0.125)10=(6.625)10
(2)十进制数→二进制数。整数部分的转换采用“除2取余”法。十进制数整数部分除以2,余数作为相应二进制数整数部分的最低位;用所得的商再除以2,余数作为二进制数的次低位……一直除到商为0,最后一步的余数作为二进制数的最高位。
例如:将十进制数11转换为二进制数的过程如下:
除法 商 余数
11÷2 5 1
5÷2 2 1
2÷2 1 0
1÷2 0 1
故(11)10=(1011)2。
小数部分的转换采用“乘2取整”法:十进制小数部分乘2,积的整数部分为相应二进制数小数部分的最高位;用所得积的小数部分再乘2,同样取积的整数部分作为相应二进制数小数部分的次高位……一直乘到积的小数部分为0或达到所要求的精度为止。
例如:将十进制数0.625转换为二进制数的过程如下:
乘法 积的整数部分 积的小数部分
0.625×2 1 0.25
0.25×2 0 0.5
0.5×2 1 0
故(0.625)10=(0.101)2。
1.3.2 数在计算机内的表示方法
1.信息度量单位
无论是数值型数据,还是字符(包括英文字符、汉字或其他符号)都是存储在一个称为字节的单元中。一个二进制位称为位(bit),8个二进制位组成一个字节(Byte),更大的度量单位是KB、MB、GB、TB。1KB=1024B,1MB=1024KB,1GB=1024MB,1TB=1024GB。计算机信息处理的最小单位是位,而计算机寻址的单位是字节。
2.原码
我们知道:数据在计算机内使用二进制形式表示。二进制数在计算机内究竟如何存储呢?可以使用原码(True form)、反码(One’s complement)和补码(Two’s complement)。
以下讨论假设使用8位二进制表示。用其中一位表示数的符号,用0表示正数,用1表示负数。数值部分用其余7位以二进制形式表示。我们看看下面两个数的8位原码表示。
在原码表示法中,数值0有两种表示方法,即正0和负0。简记为[+0]=00000000,
[-0]=10000000。
3.反码
反码又译作“对1的补码”。符号位与原码约定相同;正数的反码与原码相同,负数的反码是在原码的基础上按位取反。如[+27]反=[+27]原=00011011,而[-37]反=11011010。
在反码表示法中,数值0也有两种表示方法,即正0和负0。简记为[+0]=00000000,[-0]=11111111。
反码表示法的优点是统一了加减法运算,只需要计算加法。反码表示法的缺点是运算时会引起循环进位,这既占用机器计算时间,又给机器设计带来麻烦。因此,人们又寻求另一种表示方法:补码。
4.补码
补码又译作“对2的补码”。符号位与原码约定相同;正数的补码与原码相同,负数的补码是在原码的基础上按位取反后,最后位加1。如[+27]补=[+27]原=00011011,而[-37]补=11011011。
在补码表示法中,0有唯一的表示方法:[+0]补=[-0]补=00000000。
引入补码概念后,加法、减法都可用加法实现。因此,现代计算机多采用补码运算。
在讨论原码时我们已经假设使用8位二进制表示数,即假设计算机的字长是8位。因为要用一位表示符号,所以只有7位用来表示数据,那么在这台计算机上数据的表示范围是:-128~+127。当实际数据不在这个范围内就会出错,这就是溢出。当然现代的计算机的字长大于8位(16、32或64位),但终究有一个范围。对于溢出问题,计算机要作相应处理。
前面讨论的3种表示方法只能表示单纯整数或小数,我们认为是数的定点表示法。在计算机中,参与运算的数一般是实数,既有整数部分又有小数部分,为了表示实数,使用数的浮点表示方法。任何一个实数可以表示成A=2i×S,其中S是实数A的尾数,S的符号可用CS表示,0表示正数,1表示负数;i是用二进制表示的阶码,i的符号可用Ci表示,0表示正数,1表示负数。例如,实数110.101可表示成:211×0.110101。浮点的表示方法格式如下:
Ci、CS各只用一位,i的位数决定实数的表示范围,S的位数决定实数的精度。
计算机内的数值运算以加法为基础,其他运算都可以变成加法实现。然而现代的微处理器内已集成了浮点运算部件,其中包括了乘法器等,以提高运算速度。
1.3.3 编码(字符在计算机内的表示方法)
字符在计算机内是用二进制形式表示的,其中包括字符与汉字。
1.ASCII编码
当今的计算机普遍采用ASCII编码,即美国标准信息交换码(American Standard Code for Information Interchange)。ASCII码中的字符用8位二进制数表示,但只用低7位,共表示128个字符,编码从0至127(称为ASCII码基本集),128至255的编码(称为ASCII码扩展集)作它用。如字符“A”的编码表示如下:
ASCII字符编码如表1-1所示。编码从0至31表示控制字符,控制字符对照表如表1-2所示。
表1-1 ASCII字符编码表
表1-2 控制字符及其作用对照表
2.汉字编码
汉字编码包括汉字内码、汉字输入编码(外码)和汉字输出编码(字模)3个主要内容。
(1)汉字内码。汉字内码是汉字在计算机内的存储表示。汉字数量庞大,只能选取部分汉字用于计算机汉字信息处理。国家标准GB 2312—1980定义了国标码(区位码),它包括7445个汉字和符号,分为94个区,区号为1至94,每区容纳94个汉字或符号(汉字在区内的排列位置称为位),位号为1至94,可对应94个汉字或94个符号。其中682个符号在第1区至第9区;第10区至第15区未用;6763个汉字分为两级,一级字库从第16区至第55区,包括3755个常用汉字,按音序排列;二级字库从第56区至第87区,包括3008个次常用汉字,按笔画数排列。请读者注意,国标码是4位十六进制数,按上面的定义,“啊”字在第16区第01位上,十进制数“1601”并不是“啊”字的国标码(实际上是其区位码,区位码是一种汉字输入方法,讨论输入编码时将介绍),国标码是将某字的区位码之区、位分别转换成十六进制数,分别加上十六进制数“20”。故“啊”字的国标码为“3021”。每一个汉字或符号在区位码代码集或国标码代码集中都有唯一的代码。
汉字内码可使用ASCII码扩展集的代码(128~255),但因汉字数量众多,用一字节无法表示,所以用两个连续的字节来存放一个汉字的内码。汉字字符(用汉字内码表示)必须与英文字符(用ASCII码表示)能相互区别,以免造成混淆,这也就是所谓的中西文兼容问题。英文字符的机内代码是7位ASCII码,最高位为“0”(即b7=0),汉字内码中两个字节的最高位均为“1”。将某汉字的国标码分别加上80H,作为汉字内码。以汉字“啊”为例,国标码为3021H,汉字内码为B0A1H。
由于国家标准GB 2312—1980汉字集收录的汉字有限,不能完全满足现在的应用需要,现在又推出了国家标准GB 18030—2005。GB 18030—2005标准收录了总计23940码位,共收入21886个汉字和图形符号,其中汉字(包括部首和构件)21003个,图形符号883个。包括GB 2312—1980集中的6763个汉字,GB2312—1980集中的汉字编码不变。增加的汉字一部分采用2字节编码,一部分采用4字节编码。
(2)汉字输入编码(外码)。汉字的输入不能像英文字符那样,一键对应一个字符,只能多键输入一个汉字,这里的多键就是一个汉字的输入编码。可见,汉字输入编码是将汉字输入到计算机内(变成汉字内码)的编码,所以有人称之为外码。目前有几百种汉字输入编码。我们列举具有代表性的几种输入编码。
①区位码:一个汉字的区位码是一个4位十进制数。如汉字“啊”的区位码为1601。用区位码输入汉字实际上是将区位码转换成汉字内码。这是一种无重码(重码是一个输入编码对应多个汉字)输入方法,即一个输入编码对应一个汉字(内码)。
②拼音输入编码:用汉字的拼音符号作为输入编码。如汉字“湖”的拼音是“hu”,这就是其拼音输入编码。用拼音输入方法输入汉字就是把像“hu”这样的输入编码变成所表达的汉字的内码。显然,拼音输入方法是一种有重码的输入方法。
③字形输入编码:是一种以汉字的偏旁部首作基本键位的输入编码,即把键盘上的某一键位当作偏旁部首(当然,某一键位可能代表多个偏旁部首),多个键位(对应多个偏旁部首)的组合就是汉字的字形输入编码。五笔字型输入编码属于这一类输入编码,它是目前用得相当广泛的输入编码。例如,在五笔字型输入方案中,“湖”字的3个偏旁部首“氵”“、“古”“、“月”分别安排在键盘的“i”“d”“e”3个键位上,那么“ide”字串就是“湖”字的五笔字型输入编码。
一般来说,字形输入编码输入方法的重码少于拼音输入方法,输入速度快;而拼音输入方法易学,输入速度慢。
(3)汉字输出编码。把某一个汉字当作一幅平面图画。分别从纵、横两个方向等距离在画上画(N-1)条直线,这样就把该幅画分成N×N小方块,我们会发现有的小方块内有汉字的笔画,有的则没有。把有笔画的小方块记上“1”,没有笔画的小方块记上“0”,就得到了一幅由“1”组成的该汉字的轮廓画,这就是一幅数值化了的图形。图1-1给出了一个16×16点阵“大”字的数值化图形。当然此图中的汉字比较粗糙。按照此构思可以为每个汉字构造这样的图形。对于任何一个汉字,可以把其数值化了的平面的“0”“1”图形按先行后列(也可先列后行)的顺序编成二进制代码串存入计算机中(每一个“0”或“1”用一个二进制位存储)。我们把这样数值化的图形叫做某汉字的N×N点阵字模。对于一个16×16点阵的汉字字模,需要16×16个二进制位来存储其字模,即需要32字节。图1-1中的“大”的32字节数据(按先行后列顺序,16进制)是:00、00、03、80、03、04、7F、FE、7F、FE、27、00、06、80、0C、40、0C、60、18、30、18、30、30、18、30、18、20、0C、40、0E、00、00。
图1-1 16×16点阵模型
所有汉字的字模集合称为字库。对于用16×16点阵字模组成的字库需要大约220KB存储容量。汉字字模在字库中的位置按汉字内码升序存入字库中。