第5章 数据的表示与运算 电子数字计算机问世至今,其应用范围越来越广泛。但是本质上它仍然是一个信息处理的工具。也就是说,不管计算机的功能多么强大,都是通过对相关信息进行加工处理来完成的。这就涉及一些基本问题: 需要计算机处理的信息在计算机中如何表示?对于不同性质的信息计算机如何区别?计算机运算和人工计算的方法一样吗?这些运算是靠什么来完成的?本章将针对上述问题,着重讨论信息的机内表示方法、计算机的运算方法、基本运算部件的逻辑实现等内容。通过讨论向读者介绍计算机中运算器部件的基本工作原理和组成方式。 5.1计算机中表示信息的基本方法 5.1.1计算机中常用的信息类型 随着计算机应用领域的不断拓展,现代计算机不仅需要处理传统的科学计算领域的数值问题,而且需要处理大量非数值领域的问题。因此,计算机中处理的信息类型除了数字,还有文字、符号、图形、图像、音频和视频等多种形式。不管信息在计算机外部以何种形式出现,在送到计算机中进行处理时,都必须进行数字化编码,也就是要转换成离散的数字量形式才能由计算机识别,进而在计算机内部进行保存、加工与传送。这样做是由计算机内部采用数字电路的结构特点所决定的。 1. 数字化编码的基本原则 数字化编码的基本原则: 用少量、简单的基本符号,按照一定的组合规则,表示出大量复杂、多样的信息。基本符号的种类和其组合规则构成了信息编码的两大要素。像日常生活中熟悉的十进制数,采用0~9十个阿拉伯数码等作为基本符号,通过其特定的组合规则表示出了庞大的数值体系。 那么,什么样的数字化编码适合在计算机中实现呢? 早在1945年第一台电子计算机ENIAC的研制过程中,冯·诺依曼对其优缺点进行了深入的分析研究,提出了一台新机器的设计方案。在关于存储程序机设想的科学报告中,他明确指出,电子元件的机器不应采用人们习惯使用的十进制而应采用二进制。因此,目前在电子数字计算机中,广泛采用二进制编码(基二码)来表示各种不同的信息。 2. 基二码的特点 计算机内部采用二进制编码的好处大致可归纳为以下几点。 1) 易于物理实现 一位二进制编码仅有“0”“1”两个基本符号,可以很方便地使用具有两个稳定状态的物理器件实现,例如电位的高、低,脉冲的有、无等。而电子元件的双稳态工作性质和开关特性正好适用。 2) 运算的简易性 二进制的编码、计数和算术运算规则最简单,因此执行基本算术运算也最快。二进制的两个基本符号“0”和“1”正好与逻辑命题的“真”和“假”相对应,为程序中大量的逻辑判断提供了便利的条件。 3) 很高的经济性 与采用十进制表示数据相比,二进制表示使用的器材更少、更经济。 4) 适合逻辑代数的应用 采用二进制就面向着使用二值逻辑,很适合用数字逻辑电路来实现其内部结构,而且特别有利于采用逻辑代数作为数学工具来分析、设计和简化计算机内部大量的逻辑线路。 3. 计算机中常用的信息类型 计算机内采用二进制编码表示所有信息之后所面临的关键问题是,计算机如何对这些形式上相同但含义不同的信息加以区别?解决这个问题的基本思路: 针对不同的信息制定出具有不同解释规则的基二码,即所谓的机内数据表示。对于“数据”这个名词,人们习惯于片面地理解为数学中使用的“数”的概念。而在计算机中,“数据”泛指所有需要进行加工处理的信息,不仅包括具有数值的数,而且还包括许多本身并没有数值含义的信息,常见的有逻辑数、字符、汉字、音频信号、视频、 图51计算机中常用信息综览 图像等。其中,音频、视频信号的表示通常归结为一种新的专门信息类别,称为多媒体, 对此本书不做讨论。除了多媒体信息之外,目前计算机中常见的数据大体可以分为数值数据和非数值数据两大类。本章将按照这种分类形式对常用的信息表示方法给以介绍,图51对这些数据种类进行了概括。本节将着重讨论非数值数据、十进制数据在计算机中的表示方法,二进制数值数据的表示则在后继章节中进行专门的讨论。 5.1.2非数值数据的表示 1. 逻辑数的表示 逻辑数用二进制的两个基本符号“1”和“0”来表示“是”与“否”或“真”与“假”两种逻辑状态。在这里,“1”和“0”不再被解释成数值的大小,只具有逻辑意义。一个逻辑值需要用一位二进制(bit)表示。为了适应冯·诺依曼机中运算部件以字或字节为单位、多位同时处理的特点,逻辑数通常将多个或一组逻辑值按字节(8位)或机器字长的规模进行组织,以二进制位串的形式在机内表示。逻辑数虽然形式上和普通的二进制数据一样,但含义是完全不同的,具有按位操作、位与位之间相互独立、无位权、无进位及借位关系等特点。由于逻辑数与数值数据都是一串二进制的0/1序列,形式无任何差异,因此计算机中需要通过不同指令来区别它们。例如,逻辑运算指令默认操作数为逻辑数,而算术运算指令默认操作数是数值数据。 逻辑数是计算机中十分重要的数据类型,因为计算机内部硬件实现的基础是逻辑线路,而逻辑线路能够直接处理的对象就是逻辑数,通常称为逻辑变量。另外,计算机中需要输出的控制信号序列、外部输入计算机的大量状态感应信号等信息形式都可以作为逻辑数据进行发送、测试和处理。为了支持逻辑数的操作,计算机的指令系统中通常都会安排逻辑运算类的指令,像MIPS指令集中的AND(与)、OR(或)、NOR(非或)等,Intel 80x86微处理器系列的NOT(非)、XOR(异或)和TEST(测试)等都是常见的逻辑指令。相应地,在常用的高级语言中也有支持逻辑数据处理的运算类型,像C语言就安排有&(按位AND)、|(按位OR)、~(按位NOT)等运算。逻辑运算的相关内容见本书5.3.8节的介绍。 接下来的讨论可能会涉及大量的数据编码,为了方便表示,本书使用常用扩展名字母来表示不同数制的数据。例如,后缀B表示这个数是二进制数(Binary); Q表示八进制数(Octal); H表示十六进制数(Hexadecimai); D表示十进制数(Decimal)。十进制是我们日常使用最多的数制,因此书写时经常省略D,而其他进制的数据书写时后缀一般不可省略。但由于本教材涉及大量对二进制数的讨论,故为简便起见,在不会引起混淆的前提下,书中在给出二进制数据时也经常省略其扩展名。 2. 字符的表示 字符通常指通信行业或人—机交互时大量使用的字母、数字、专用符号等西文信息,是人与计算机进行联系的重要媒介。像书写时常用的英文字母、标点符号、十进制的阿拉伯数码、数学符号等都属于字符范畴。人们日常对字符的表示是基于其字形,但是计算机中的数字电路是无法直接表示出形象符号的,仍然需要借助二进制编码的方式进行表示。当采用二进制编码表示字符时,可把字符看成是计算机中的一种符号数据。对字符进行编码的关键是要保证每个字符都有唯一确定的编码值,这样才能作为识别与使用这些字符的依据。由于西文是一种拼音文字,用有限数量的字母就可以拼写出所有单词,再加上常用的数学符号、标点符号等辅助字符,因此西文字符集的字符总数不是很多,通常每个字符编码使用7~8个二进制位表示即可。 1) 字符的交换码标准 有关字符编码的方案很多,目前国际上普遍采用的一种字符编码系统是ASCII码,即美国标准信息交换码(American Standard Code for Information Interchange)。它用7位二进制编码表示一个特定的字符,因此ASCII 码字符集总共定义了128种字符编码。 在28种ASCII 码字符中,有95种字符基本上是日常西文书写时常用的字母或符号,它们的共同特点是“有形”,在把这些字符输入到计算机中时,可在计算机键盘上找到标有这些字母或符号的键,通过敲击这些键就可以把所选的字符送到计算机中。这些字符也可由计算机终端显示输出,或由打印设备进行打印,被称为可显示或可印刷字符。另外33种编码则不可以显示或打印,主要用来控制某些外部设备的动作和某些软件的运行方式,以及通信控制等,被称作控制字符。 2) ASCII码的机内表示 ASCII码只是一种通用的信息交换码标准,主要解决数字通信系统之间信息传送的相互兼容问题。当用于计算机中表示字符时,还要考虑ASCII码的格式与机内数据格式的一致性。由于目前计算机中习惯以字节为单位表示数据,所以ASCII码在机内也是用一个字节来进行表示。但是,ASCII码只占用了8个字节中的低7位,字节的最高位取值还需要加以确定。对这一位常用的处理方法有如下几种: (1) 最高位恒为“0”,此时可利用这一位作为ASCII码的识别标志。 (2) 最高位用于奇偶校验位,根据奇偶校验技术的需要取值“0”或“1”。 (3) 采用扩展ASCII码方案时,最高位也可用作字符编码。例如,将ASCII码扩展到8位,字符集扩大到256种字符。除保留ASCII码原有字符之外,可以增加制表符、计算符、希腊字母和拉丁符号等。 3) 字符串的表示 ASCII机内码解决了单个字符在计算机中的表示问题。但在实际的文字处理等应用场合,使用单个字符的情况并不太多,大量的字符通常都是成串出现的,把这种由连续一串字符组成的数据形式称为字符串。目前,字符串已成为计算机中最常用的数据类型之一,许多计算机的指令系统中都提供了支持字符串存取和处理功能的串操作类型的机器指令,如Intel 80x86指令系统中的串处理指令MOVS、CMPS、SCAS等。 由于ASCII机内码已解决了单个字符在计算机中的表示问题,因此字符串在机内表示时需要解决的关键问题是其在主存中的存放方式。最常用的一种方法称为向量表示法。用它表示字符串时,将字符串存放在主存的连续多个字节单元中,每个字节单元保存串中一个字符的ASCII码。在字长较长且主存按字节编址的计算机中,主存单元通常由2个(16位机)或4个(32位机)字节单元组成。此时如采用向量表示法表示字符串,在同一个主存单元中,既可按从低字节单元向高字节单元的顺序存放字符串,也可按从高字节单元向低字节单元的顺序存放字符串。这两种存放方式都很常用,不同的计算机可能会选用其中一种,到底采用哪一种则主要取决于该机主存字节单元的编址顺序。 例如,现在有这样一个字符串: “if (A<B) READ(C)”,其对应的ASCII码的十六进制值依次为69H,66H,20H,28H,41H,3CH,42H,29H,20H,52H,45H,41H,44H,28H,43H,29H。当这个字符串在主存中按从高字节单元向低字节单元的顺序存放时,主存空间占用方式如图52所示,其中主存单元长度为32位,由4个字节单元组成。 图52字符串从高到低字节单元存放的方案 采用向量表示法表示字符串时,需要给出串首地址和串长这样两个表征参数来描述字符串在主存中的位置,也可使用特定的结束符来表示字符串的末尾,在给出结束符的情况下串长参数则可省略。向量表示法是最简单、最节省存储空间的字符串存放方法。但是,在进行字符串删除和插入操作时,对被删除或插入的字符后面的剩余字符串部分需要全部重新分配存储空间。在字符串较长的情况下,这将花费较多的时间。 3. 汉字的表示 与国际上广泛采用英文作为文字处理对象的情况有所不同,我国大量使用的语言文字是汉字。计算机要对中文信息进行处理,就必须采用表示西文字符类似的方法,在机内对汉字进行二进制编码。但与西文相比,汉字属大字符集语种,文字数量巨大,其总数可达数万字,这导致汉字编码所需的二进制位数大大增加。不仅如此,如何使用西文键盘输入汉字?如何将二进制编码表示的汉字输出显示或打印出来?汉字在计算机中如何表示、处理、输入和输出的一系列问题都需要使用专门的方法加以解决。 为了满足计算机对汉字信息的输入、处理、输出等不同工作阶段的特殊需求,汉字处理系统配置了几种性质不同的汉字编码方案,分别用于汉字处理的不同场合。 1) 汉字输入码 计算机最早是由西方国家研制的,采用了西文标准键盘作为其最主要的信息输入设备,但经过几十年的发展,到现在绝大多数的计算机仍然继续采用西文标准键盘作为主要的信息输入手段。西文标准键盘的按键排列方式基本上沿袭了西文打字机的键盘布局,一个或两个西文字符对应着一个按键,并充分考虑了盲打指法和速度上的要求,输入英文等西文时使用起来非常方便。但是如果用来输入汉字,由于汉字的数目众多,结构也与西方文字完全不同,因此西文键盘无法像输入英文那样直接提供与之一一对应的关系。 为利用西文标准键盘直接输入汉字,广泛采用的解决方法是为汉字设计专门的输入编码。与二进制编码概念不同的是,汉字输入码的码元(组成编码的基本元素)是西文键盘中的某个按键,每个汉字用一个或几个键的特定组合表示。我国的汉字输入码方案很多,但真正推广应用较好的只有少数几种。能够被广泛接受的汉字输入码方案一般具有易学、易记、效率高(击键次数较少)、重码少、容量大(包含的字数多)等特点。 到目前为止还没有一种方案在所有方面都做到很好。常用的汉字输入码方案大体分以下四类: 数字编码、字音编码、字形编码和形音编码。由于汉字输入码仅仅解决汉字的键盘输入问题,因此为与汉字的机内编码相区别,汉字输入码又称为汉字机外码或“外码”。实际上,不管采用哪种汉字输入码方案其实质都是一样的,都是利用键盘进行“手动”输入。比较理想的输入方式是利用语音或图像识别技术“自动”将汉字文本输入到计算机内,并将其自动转换为机内代码表示。目前,已经有手写汉字联机识别输入、汉字扫描输入后自动识别、语音输入汉字等。 2) 汉字交换码标准 为了便于不同的信息处理系统之间相互通信以及汉字信息交换的使用需要,早在1981年我国就颁布了汉字交换码标准,即《信息交换用汉字编码字符集 基本集》(GB 2312—1980),这个标准称为国标码,又称国标交换码。该标准共收入6763个常用汉字,并按其使用频度对这些汉字进行了分类。其中一级汉字3755 个,属于常用汉字,按汉语拼音排序; 二级汉字3008 个,属于次常用字,因为使用频度降低,所以按偏旁部首排序。此外,一些常用的字母、数字和符号也收入了该标准的字符集,包括英文、俄文、日文平假名与片假名、罗马字母、汉语拼音等共687个。 GB 2312—1980汉字交换码标准为字符集中的每一种汉字或其他字符规定了一个唯一的二进制代码。这些代码以代码表的形式给出,代码表分成94个区(对应94行),每个区有94位(对应94列)。表中的行编号称为区号,列编号称为位号,各用7位二进制编码表示,形成一个二维数组。表中每个行、列的交叉点上都有一个汉字,交叉点所在位置的行列坐标号合起来就构成了该汉字的编码。其中,7位区号在左、7位位号在右,共14位。国标码规定区号和位号的取值范围均为十六进制的21H~7EH,这导致国标码识记起来不很直观。GB 2312—1980标准还经常采用另一种称为“国标区位码”的表示方式。区位码直接用十进制的1~94来表示汉字的区号和位号,其对应的二十进制编码(BCD码)仍以区号在左位号在右的形式表示。与国标码相比,区位码更加直观好记,因此得到了广泛的应用。 3) 汉字机内码 相对于汉字机外码而言,汉字机内码或“内码”是指汉字在计算机内部存储、处理和传送所采用的二进制编码。汉字通过输入码从键盘输入到计算机内部后(或通过语音、手写、扫描等其他手段输入),就以“内码”的形式存在于机内。也就是说,不管汉字采用何种方式输入,都必须转换成机内码才能被计算机存储和处理。因此,汉字机内码与所采用的汉字输入法无关。不同的计算机系统中采用何种汉字机内码方案并没有统一的规定,目前较为广泛的是将国标码或国标区位码用于汉字的机内表示。但与ASCII码机内表示的情况类似,国标码如果直接作为机内码使用,格式上还需要适应计算机内部数据的表示形式。另外,计算机中的中西文信息经常混合在一起进行处理,汉字机内码需要予以特别的标识,才能与ASCII机内码加以区别。现以采用GB 2312—1980方案为例,常用的汉字机内码设定方法如下: (1) 若ASCII码采用字节最高位恒为“0”的机内表示方案,则通常用两个字节表示一个汉字,两个字节的最高位均设为“1”,每个字节的低7位为国标码或国标区位码。 (2) 若ASCII机内码字节的最高位用于奇偶校验位或扩展ASCII码,则需要3个字节表示汉字,其中第一个字节作为汉字的标识符使用。 仍以“红”字为例,其国标码为3A6CH,如采用上述两个字节最高位均为“1”的表示方案,则对应的机内码为BAECH。应当注意,汉字的国标码或区位码是唯一的通用标准编码,而汉字机内码在不同的系统中可能会采用不同的方案实现。 4) 汉字字模码 汉字机内码解决了汉字在计算机内部的编码表示问题。可是,经过计算机处理后的汉字如果需要显示或打印,就必须将二进制编码形式的汉字机内码转换成汉字原来的、可供人们阅读的方块字形式。汉字字模码就是为输出设备输出汉字而设计的字形编码。 汉字的字形主要有两种描述方法: 点阵描述和轮廓描述。点阵描述是将汉字的字形用“点”组成的方阵来表示,方阵中有笔画的点位点上黑点,这样我们就可以看到一个用“点”排列出来的汉字。由于汉字的字形较为复杂,因此要能够清晰地描述一个汉字,至少需要16×16左右大小的点阵规模。如果希望“点”出来的汉字更好看,还可以使用更大的点阵,如24×24、32×32,甚至更大。 5.1.3十进制数据的编码表示 现在我们已经知道计算机内部表示数据的基本方法是采用基二码,而在日常生活中人们习惯使用十进制进行计算,这就导致了计算机内部、外部数据形式的不一致。因此在多数应用环境中,计算机输入数据时通常要将十进制转换成二进制,而输出时又需将二进制转换成十进制。在某些特定的应用领域如商业统计中,需要进行的运算很简单但数据量很大,这样输入输出过程中进制转换所占的时间比例就会很大。从提高机器运行效率的角度出发应尽量减少这种转换。另外,十进制转换成二进制可能会造成数据精度的损失,这在精度要求较高的应用中也是不希望出现的。这些特定场合都对计算机内部能够直接用十进制表示和处理数据提出了要求。为适应这方面的需要,目前大多数通用性较强的计算机中都具有直接表示和处理十进制数据的能力。 1. 十进制数的BCD码表示 在计算机内部直接表示十进制数据的基本思路仍然是使其二进制代码化。要使0~9这十个阿拉伯数码分别拥有一个唯一的二进制编码,至少需要4位二进制码表示。由于4位二进制码共有16种组合,而表示一位十进制数只需选取其中10种,这就使剩下的6种变成了冗余的无用组合。如何从16种组合中选择10种来表示一位十进制数,可供选择的编码方案很多,但比较常用的也只有少数几种。这些编码统称为二进制编码的十进制数(Binary Coded Decimal),简称BCD码或二十进制码。常用的BCD码按照其位权设置方法的区别,可分为有权码、无权码等。 1) 十进制有权码 有权码是指用来表示一个十进制数字的若干二进制数位的每一位都有一个确定的位权,将这些二进制编码中取值为“1”的数位的权值加到一起,就得到了对应的十进制数值。最常用的一种有权码就是8421码。8421码4个二进制数位的位权从高到低分别为8、4、2和1,故称8421码。这种编码方案选取4位二进制编码的前10种顺序组合0000、0001、…、1001来表示0~9这10个十进制数字,正好和二进制数的0~9取值一致,因此也叫作自然的二进制编码的十进制数(Natural Binary Coded Decimal, NBCD)。8421码的另一特点是与十进制数0~9的ASCII码低4位取值相同,这使8421码与ASCII码以及二进制数之间转换很方便。8421码虽然具有简单直观便于转换的优点,但在计算机内实现算术运算要复杂一些,在某些情况下需要对加法运算的结果进行修正。关于这一点我们将会在运算方法部分进一步讨论。另外几种有权码如 2421码、5211码、4311码等与8421码的定义方法类似,表51列出了这些常用的十进制有权码。 表514位十进制有权码 十进制数8421码2421码5211码4311码 00000000000000000 10001000100010001 20010001000110011 30011001101010100 40100010001111000 50101101110000111 60110110010101011 70111110111001100 81000111011101110 91001111111111111 2) 十进制无权码 另一类常用的二十进制编码方案是十进制无权码。与有权码表示方法相反,无权码是指用来表示一个十进制数字的4个二进制数位的每一位均没有确定的位权。在无权码方案中,使用较多的是余3 码和格雷码。余3码是在8421 码的基础上加3(即二进制的0011)得到,故称“余3”码。也就是说,余3码选取了4位二进制编码16种组合中的中间10种组合来表示一位十进制数。余3码的表示方法虽然没有8421码直观和转换方便,但在执行十进制加法时,能自动产生出十进制进位信号,有效地简化了进位修正逻辑电路。另外,余3码还具有“自补码”的特性,给十进制减法运算的实现也带来方便。这里所谓的“自补码”是指,如果将某个十进制数的二十进制编码按位“求反”,就可得到该数相对于9的补码。除了余3码以外,表51中的2421码、5211码等有权码也属于“自补码”,而8421码则不具此特性。 格雷码又称循环码。其编码规则是任何两个相邻十进制数字的二十进制编码只有一位二进制位状态不同,其余3个二进制位的状态必须相同。这样在进行十进制计数时,从一个编码变到下一个编码只有一位二进制位发生状态翻转。这样转换速度达到最快,且有利于得到更加可靠的译码波形,避免了两位以上状态同时翻转带来的不稳定因素,被广泛用于可靠性要求较高的计数电路中,如用来产生平滑改变的控制信号,以及模拟数字转换信号等场合。由于4位二进制组合中6种冗余状态的存在,用格雷码表示十进制数的方案很多。表52列出了常用的十进制无权码方案,其中有两种是格雷码。 表524位十进制无权码 十进制数余3码格雷码(1)格雷码(2) 0001100000000 1010000010100 2010100110110 3011000100010 4011101101010 5100011101011 6100110100011 7101010000001 8101111001001 9110001001000 2. 十进制数串的表示 BCD码解决了一位十进制数的机内表示问题。但机内直接采用十进制表示的另一个目的是提高数据的表示范围和运算精度。计算机中的二进制数据由于受字长的限制,可表示的范围和精度是有限的。如果将十进制数转换成二进制进行运算,可能会造成精度的损失。但如果将多位十进制数以数字串的形式直接输入计算机,就可以摆脱二进制机内数据格式的约束。 十进制数串在计算机内主要有以下两种表示形式。 1) 字符串形式 这种表示法把一串十进制数看成一串字符串,采用类似于字符串的表示方法,串中每位十进制数以及正、负号均用对应的ASCII码表示。根据数符的不同安排,此方法又可分为前分隔数字串和后嵌入数字串两种形式。 (1) 前分隔数字串: 前分隔数字串表示方法与日常书写顺序相同,是将数符置于十进制数串之前,单独用一个字节来表示。正号用字符“+”的ASCII 码(2BH)给出,负号用字符“-”的ASCII 码(2DH)给出。例如,十进制数+236可表示为2BH 32H 33H 36H,在内存中占用4个字节; 十进制数-2369可表示为2DH 32H 33H 36H 39H,在内存中占用5个字节。 (2) 后嵌入数字串: 采用后嵌入数字串方式时,数的符号不再单独用一个字节来表示,而是嵌入到最低一位数字的ASCII码中。具体规定为: 正数最低一位数字的ASCII编码不变; 负数最低一位数字的ASCII码的高4位由原来的0011变为0111。仍以上面的两个数串为例,+236此时表示为32H 33H 36H,在内存中占用3个字节; 而-2369则表示为32H 33H 36H 79H,在内存中占用4个字节。这样,后嵌入数字串方式比前分隔数字串方式少占用一个字节,节省了存储空间。但负数的最低一位数字已不再是ASCII码形式,在显示或打印前必须先转换回ASCII码。从这一角度看,后嵌入数字串又没有前分隔数字串方式输入输出来得方便。 用字符串方式表示十进制数串方便了十进制数的输入输出,但是对十进制数的机内运算来说却很不方便。因为阿拉伯数字0~9的 ASCII码高4位的值并不具有数值意义,必须先去掉转换为二进制数或BCD码才能进行算术运算。所以这种方式表示的十进制数串主要应用于非数值计算领域。 2) 压缩的十进制数串形式 这种方法在表示十进制数串时,把串中每位十进制数的ASCII码高4位压缩掉,只用其低4位表示(也可看成直接用8421码表示)。这样每个十进制数位只需占半个字节的存储空间,一个字节单元就可存放两个十进制数位,比字符串表示方式要少占用一半左右的存储空间。此时十进制数串的符号也占用半个字节并存放在最低数位之后,其值可选用4位二进制编码中8421码不用的6种冗余状态的两种不同值即可。通常用1100表示正号,1101表示负号。这种表示方式规定十进制数串的数值位加符号位之和必须为偶数,如不为偶数应在最高数位之前补一个0。例如,+123被表示成123CH,-12被表示成012DH。此表示法指明一个十进制数串时也需给出它在主存中的首地址和十进制数字的位数(又称为位长,不含符号位)。位长为0的数其值也为0。压缩的十进制数串位长可变,许多机器中规定该长度为0~31,有的甚至更长。另外,它比字符串表示形式节省存储空间,又便于直接完成十进制数的算术运算,是广泛采用的较为理想的表示方法。 虽然采用BCD码和十进制数串的方法可以在计算机中直接表示十进制数,但需要占用更多的硬件资源。例如,处理1000以内的信息,需要3位十进制数,再加上符号位,因而至少需要(3+1)×4=16位的设备量。而对于二进制系统来说,210=1024,只需 10位的设备量就足够了。因此除非特殊需要,通常情况下计算机内部都用二进制数进行数据的表示和运算。 5.2定点数的表示 5.2.1真值与机器数 1. 数符的机内表示 计算机中表示数值数据时,不仅要考虑采用何种进位计数制比较方便,还需要解决数的符号表示问题。数值数据通常有无符号数和有符号数之分。所谓无符号数,就是不考虑数的正负符号,相当于数的绝对值。此时整个机器字长的全部二进制位均可用来表示数值。例如,X=(0100 1010)2表示无符号数74; Y=(1100 1101)2表示无符号数205。若机器字长为8位,则无符号数的表示范围为0~255。当机器字长为n+1位时,无符号数的表示范围是0~(2n+1-1)。一般计算机中都设置有一些无符号数的运算和处理指令。如 Intel 8086 中的 MUL和 DIV指令就是无符号数的乘法和除法指令,还有一些条件转移指令也是专门针对无符号数的。 然而,在进行数学计算时,大量用到的还是有符号数,即带有正、负号的数。日常生活中通常采用特定的数学符号“+”“-”来表示数的正负,可是这样的符号在计算机中是无法直接表示的。解决的方法又回到了前面讨论的基本思路上,就是把符号二进制数码化,“0”“1”两种代码正好可用来表示数的正、负两种符号。根据这个思想,计算机中在表示有符号数时,一般在最高数值位之前再安排一位专门用来表示数的符号,称为“符号位”,这样就解决了数符的机内表示问题,如图53所示。 图53数符的机内表示 注意符号位仅用来表示数符,不具有数值意义。由于无符号数不需要安排符号位,因此在同样机器字长的情况下,比有符号数的表示范围大一倍。例如,设符号位为0表示正数,为1表示负数,则前面给出的数据用来表示有符号数时,X=(0100 1010)2的十进制真值为+74; Y=(1100 1101)2 则对应十进制真值为-77。在对数的正负号表示作了代码化处理之后,计算机中的数据形式已经和通常的手写形式不一样了。为了加以区别,把计算机内的数据形式称为机器数,而把一般书写形式表示的、带正负符号“+”“-”的数称为机器数的真值。不难看出、无符号数的机器数形式和其二进制真值是一致的,而有符号数的机器数与真值之间的关系则没有这样简单,通常根据符号位与数值位之间的不同编码组合形式又分为原码、反码、补码等不同的表示方式,这个问题将在后续5.2.3节中进行详细讨论。 2. 小数点的机内定位 数值数据的机内表示还有一个关键问题需要解决,那就是小数点的定位。这个问题的难点在于小数点在数据格式中无法再用二进制代码表示。我们不妨换一种思路来寻求解决办法,实际上在计算机中通常以“隐含”方式来表示小数点的位置,就是说只要事先约定好小数点的位置,按照这个约定来识别数值即可,数据格式中并不需要明显地给出小数点。目前计算机中采用的小数点表示法分为定点和浮点两种形式。在此,先对比较简单的定点表示法进行讨论,浮点表示法较为复杂,在本章5.5节中将进行专门的阐述。 所谓定点表示法指小数点的位置在一台计算机中是事先约定好且固定不变的。通常采用的定位方式有两种: 一种将小数点的位置定在最低数值位之后,这导致机内的所有数据均为整数,因此称为定点整数表示法; 另一种将小数点的位置定在符号位(最高位)之后,小数点的位置定在这里就意味着机内的所有数据均为小数,因此这种方式称为定点小数表示法。两种表示方式如图54所示。 图54定点数的机内格式 定点表示法的缺点是表示范围较小,或者只能表示纯整数(定点整数表示法),或者只能表示纯小数(定点小数表示法),而对于现实计算中普遍采用的带小数形式的数据是无法直接表示的。因此这类数据在运算前需要乘上一定的比例因子,使之变为整数或小数形式,定点计算机内部才会接受。困难的是,对于非常大或非常小的数据,合适的比例因子很难找。 为了讨论方便起见,也为了能够更加清楚地区分符号位和数值位,通常习惯将有符号数的最高数值位用MSB(Most Significant Bit)表示,称为“最高有效位”; 而最低数值位则用LSB(Last Significant Bit)表示,称为最低有效位。例如,如果我们说“有符号数的最高位”,则一般是指这个数的符号位。而如果说“有符号数的MSB位”,则一定是指这个数符号位之后的最高数值位。注意由于位权关系不同,定点小数的MSB、LSB和定点整数的MSB、LSB所代表的数值是不一样的。在n位数值的情况下,定点小数的1LSB表示2-n,而定点整数的1LSB就等于1(20)。 5.2.2常用机器码表示 在将有符号数的正、负符号也用“0”“1”表示之后,就为符号位与数值位之间进行新的编码组合提供了可能性。为了便于在计算机中进行各种运算,特别是最基本的加减运算,计算机中按照有符号数的不同组合规则,提出了不同的机器数编码方案,简称“码制”。因此,机器数也常称为“机器码”。目前计算机中广泛采用的编码方法有原码、补码、反码三种。为了便于区别一个数的真值和对应的各种机器码,本书中用X表示真值,[X]原表示其原码,[X]补表示其补码, [X]反表示其反码。 1. 原码表示法 原码是最简单直观的一种机器码表示法,这种方法将机器数的最高位定义为符号位,用“0”表示正号,“1”表示负号; 数值部分则与真值保持一致,因此也常被称为“符号数值表示法”,即原码可看成是由一位符号位与数值位简单的拼接而成,其与二进制真值之间的差别仅仅在于数字的符号被二进制代码化了。这个编码规则可用数学表达式进行定义。 1) 小数的原码表示 如果n位二进制小数的真值X=±0.X1X2…Xn,则对应的原码定义为 [X]原=X0≤X<1 1-X=1+|X|-1103,可得 (210)12>(103)12,即2120>1036 又因 27>102,所以 27×2120>102×1036,即2127>1038 同理可得2-127<10-38 由上推导可知: 阶码取8位(含1位阶符),且用补码或移码表示时,对应的浮点数取值范围为2-128 ~ 2+127,可以满足题意要求。 (2) 浮点数精度的设计主要是确定尾数的位数。 由于107≈223,故尾数的数值部分可取23位,加1位数符位达24位。 最终该浮点数至少取32位,其中阶码8位(含1位阶符),尾数24位(含1位数符)。 5.5.4IEEE 754浮点标准 通过上面对浮点数表示方法和原理的讨论,我们对浮点数有了一个基本的认识。为了进一步加深对浮点表示法的理解,现在以广泛流行的IEEE 754国际标准浮点数为例,来看看实际的浮点数格式。 1. IEEE浮点格式 IEEE 754浮点标准由IEEE(电气和电子工程师协会)于1985年提出,主要为便于不同计算机系统之间的数据交换、协同工作及软件移植,浮点数的格式应该有统一的标准定义而设计。IEEE 754标准浮点数的格式与我们前面5.5.1节介绍的浮点数基本格式有一些差别,如图550所示。 图550IEEE 754标准的浮点数格式 为了便于讨论,我们把上述IEEE 754标准浮点数的格式书写为 S,EsE1E2…Ek; .M1M2…Mn 概括起来,IEEE 754标准对浮点数的格式作了如下规定(以32位为例)。 (1) 表示格式由数符S、阶码E、尾数M三部分组成。 (2) 数符位S占1位,设在浮点格式的最左边(最高位)。S的取值按原码符号位的规定,S=0表示正数,S=1表示负数。 (3) 阶码E为8位整数,用移码表示,偏置常数为+127,阶的基为2。 (4) 尾数值M为23位小数,用原码表示。 (5) 非0规格化尾数的最高有效位恒为1,采用隐藏位方案,约定该位总是躲藏在尾数小数点的左边(即位权为20,是一位整数)。因此尾数值实际上可达24位(1位隐藏位+23位小数位)。 IEEE 754标准中设定了三种常用的浮点数格式,其数位的具体分配如表511所示。 表511IEEE 754 标准中的三种浮点数 类型 数符S 阶码E 隐藏位 尾数值M 总位数 偏置常数 十六进制 十进制 短实数 1 8 有 23 32 7FH +127 长实数 1 11 有 52 64 3FFH +1023 临时实数 1 15 无 64 80 3FFFH +16383 表中短实数又称为单精度浮点数,长实数又称为双精度浮点数,它们都采用了隐藏位方案,这样实际上又增加了一位尾数。临时实数又称为扩展双精度浮点数,它不含隐藏位,常用于中间计算过程,以减少相应的精度损失。 2. 极端值的特殊规定 IEEE 754标准用阶码E的两个极端值0和全1表示一些特殊的情况,主要有下面几点: (1) 阶码E为0且尾数M为0表示浮点0。S=0表示+0,S=1表示-0。 (2) 阶码E为0且尾数M不为0,若隐藏位=0,表示非规格化数。S=0表示正非规格化数,S=1表示负非规格化数。 (3) 阶码E为全1且尾数M为0表示∞,S=0表示+∞,S=1表示-∞。 (4) 阶码E为全1且尾数M不为0,表示非数(即不是一个数),非数常用来通知各种异常条件。 3. 舍入处理方法 IEEE 754标准中还给出了四种可供选择的舍入处理方法。 (1) 就近舍入: 运算结果可被舍入成最接近的可表示数,这是该标准默认的舍入方式,其实质类似于前面介绍的“0舍1入”法。例如,假设运算结果比规定的尾数位数多出5位,若多余位取值是10010,已超过尾数最低有效位(LSB)权值的一半,故最低有效位加1,相当于“入”; 若多余位取值是01111,则简单的截尾即可,相当于“舍”; 若多余位取值是10000这种严格中点的情况,则需要根据最低有效位的取值来决定取舍。若最低有效位=0则截尾; 最低有效位=1则作加1操作。 (2) 朝0舍入: 就是简单的截尾,丢掉多余位后不作任何进一步的处理。其舍入后果总是使结果的绝对值变小(单向负误差),朝向数轴原点趋近。 (3) 朝+∞舍入: 朝正无穷大方向向上舍入。若尾数为正数,只要舍去的多余位不全为0,做最低有效位加1操作; 若尾数为负数,则简单的截尾。 (4) 朝-∞舍入: 结果朝负无穷大方向向下舍入。处理方法正好与朝+∞舍入相反,对正数来说,做简单的截尾; 对负数而言,只要多余位不全为0,做最低有效位加1操作。 4. 主要表示特点概括 综上所述,IEEE 754标准浮点数主要有下述特点: (1) 符号位放在浮点数格式的最高位,便于判0和判断符号操作的实现。 (2) 机器零为一串0的形式(E和M均为零),便于判0。 (3) 两浮点数进行大小的比较时,可不必区分阶码位和数值位,视同两定点数比较一样对待。 (4) 设置隐藏位提高尾数表示精度,且隐藏的数值为1而不是通常的2-1。 (5) 阶的移码采用2k-1而不是通常的2k作为偏置常数,通过对0或全1极端阶码值的充分利用,增加了表示的多样性。 现以单精度浮点数格式为例,32位的浮点规格化数的真值可表示为 N=(-1)S×(1.M)×2E-127(569) 其中,S代表符号位,S=0表示正数,S=1表示负数; E为阶码的移码; M为尾数的小数部分; 小数点前面的1为隐藏位。由于正常的阶码其移码值E可取1~254,则短浮点数阶码的真值范围为-126~+127。 【例5.9】写出IEEE 754标准短浮点数和长浮点数的表示范围,并进一步指出其规格化可表示的最小正数、最大负数为多少? 解: (1) 短浮点数。 根据IEEE 754标准短浮点数的格式规定,其阶码8位,移码取值范围为0~255。由于正常阶码的移码值E只能取1~254,则短浮点数阶码的真值范围为-126~+127。短浮点数的尾数23位,则 最大正数=2127×(2-2-23),最小正数=2-126 最大负数=-2-126,最小负数=-2127×(2-2-23) IEEE 754标准短浮点数表示范围为: -2127×(2-2-23) ~ 2127×(2-2-23),用10的幂可近似表示为: 10-38~1038。 (2) 长浮点数。 长浮点数的格式规定阶码11位,移码取值范围为0~2047。而正常阶码的移码值E可取1~2046,则长浮点数阶码的真值范围为-1022~+1023。长浮点数的尾数52位,其规格化数的真值可表示为N=(-1)S×(1.M)×2E-1023,则 最大正数=21023×(2-2-52),最小正数=2-1022 最大负数=-2-1022,最小负数=-21023×(2-2-52) IEEE 754标准长浮点数表示范围为: -21023×(2-2-52) ~ 21023×(2-2-52)。 通过上述例题可知,在使用IEEE 754标准浮点数时,需要特别注意隐藏位的存在。整数部分的“1”被隐含表示,在格式中不留任何痕迹。 5.5.5规格化浮点加减运算 在讨论了浮点数的表示方法之后,让我们进一步讨论浮点数的算术四则运算方法。由于浮点数的表示方法比定点数复杂得多,因此运算方法也相对复杂。出于习惯,我们对于浮点算法的讨论仍然按先加减、后乘除的顺序展开。由于计算机中普遍采用规格化浮点数,因此对浮点算法的讨论主要围绕规格化浮点运算展开。所谓规格化浮点运算是指,参加运算的操作数为规格化浮点数,运算完成后结果也是规格化浮点数。 1. 浮点加减运算基本规则 首先对浮点数阶码和尾数两部分进行分析,可知有效数值是由尾数给出的,则加减运算应在尾数部分进行。这里遇到的第一个问题是加减运算要求操作数的小数点对齐,虽然所有浮点数格式中尾数的小数点位置是一致的,但这并不能代表其小数点的实际位置。浮点数小数点的实际位置是由阶码的大小决定的。当两浮点数阶码不等时,其小数点的实际位置是不一样的,也就是小数点未对齐,此时尾数无法直接进行加减运算。故浮点加减运算的第一步必须使参加运算的两浮点数阶码相等,这一操作称为“对阶”。对阶之后,尾数就可以进行加减运算了。由于尾数的表示方式与定点小数完全相同,因此其加减运算规则也与定点小数完全相同。尾数运算完成后,还可能会涉及运算结果的规格化、精度的舍入、溢出判断等一系列问题需要进一步解决。另外,由于浮点运算比定点加减运算更费时间,因此希望尽量简化运算过程,当操作数为0时,可以考虑不实施运算。按照上面的分析,可以将浮点加减运算步骤归纳为下面几步: (1) 0检测,判断操作数是否为0; (2) 对阶,使两数的小数点位置对齐; (3) 尾数运算,两尾数按定点加减运算规则求和(差); (4) 结果规格化,若运算后尾数不再是规格化形式,进行规格化处理; (5) 舍入,为尽量避免精度损失,对尾数右移时移出的保护位进行舍入; (6) 溢出判断,运算过程中对可能发生溢出出错的操作及时判溢出。 现设有两个浮点数X和Y,分别表示为X=Mx×RE,Y=My×RE,若求Z=X±Y,则浮点加减运算的基本规则可用通式描述为: Z=X±Y=(Mx±My×2-(Ex-Ey))×2Ex,Ex≥Ey (Mx×2-(Ey-Ex)±My)×2Ey,Ex<Ey(570) 式中,2-(Ex-Ey)和2-(Ey-Ex)称为移位因子,反映对阶时尾数右移的位数。 下面让我们详细讨论每一步运算的具体操作方法。 2. 浮点加减运算步骤 1) 0操作数检测 运算前先分别对两操作数X、Y进行判0操作 若X=0,则令X+Y=Y; X-Y=-Y; 运算结束; 若Y=0,则令X+Y=X-Y=X; 运算结束。 2) 对阶 对阶的目的是使两操作数的小数点对齐,即使得两数的阶码相等。对阶前,先要进行阶码比较,确定两数的阶码是否一致。由于运算器中通常不设比较电路,因此阶码的比较是通过“求阶差”操作完成的。阶差可描述为 ΔE=Ex-Ey(571) 若ΔE=0,说明Ex=Ey,尾数可直接进行加减; 若ΔE≠0,则意味着Ex≠Ey,需要先对阶,阶码对齐后才能进行运算。 求阶差时的减法运算采用何种算法与阶码所用的码制有关,若阶码用补码表示,则可使用定点整数补码加减法进行计算。即 [ΔE]补=[Ex]补+[-Ey]补(572) 其次要解决阶码按怎样的规则对齐的问题。若大阶向小阶看齐尾数需要左移,对规格化数来说会引起尾数溢出,显然不可取; 而小阶向大阶看齐则需要尾数右移,虽然可能损失精度但对尾数的正确性没有大的影响,故规定对阶的规则为: 小阶向大阶看齐。 对阶的操作过程一般采用逐步逼近的方式,小阶每+1,其尾数右移一位,ΔE+1或-1向0趋近一步,反复进行到ΔE=0为止。为了尽量减少精度损失,对阶时尾数最低位移出的多余位可通过在运算器中设置保护位寄存器的方法,先把移出的前几位数值暂时保存起来,以便左规时再补入最低有效位,或供舍入判断之用。对阶过程具体描述如下: ΔE>0, Ex>Ey,Ey+1,My→1,ΔE-1,重复到ΔE=0为止。此时Ez=Ex; ΔE<0,Ex<Ey,Ex+1,Mx→1,ΔE+1,重复到ΔE=0为止。此时Ez=Ey。 3) 尾数相加减 对阶完成后即可进行尾数运算,按定点小数加减运算规则求Mz=Mx±My。 当尾数用补码表示时有: [Mz]补=[Mx±My]补=[Mx]补+[My]补求和 [Mx]补+[-My]补求差 4) 结果规格化 采用规格化表示时,虽然参加运算的操作数都是浮点规格化形式,但运算后结果有可能超出规格化数的表示范围,此时应对结果进行规格化处理,将其变回到规格化形式。浮点加减运算结果可能发生两种非规格化情况: (1) 尾数发生溢出,此时只要右规一次,尾数右移1位,阶码+1即可; (2) 尾数非0,未发生溢出,也不满足规格化判断条件。此时需要左规,而且还有可能需要左规多位。左规时尾数每左移1位,阶码-1,重复进行到满足规格化条件为止。随着尾数逐位左移,可以考虑将保护位逐位补入尾数的最低位。规格化处理的具体规则参见前面5.5.3节的详细介绍。 5) 舍入 对结果进行规格化处理后,可能还会剩余有若干保护位不能补充回正式的尾数位中,需要舍去。为了把结果的精度损失降为最低,通常采用特定的舍入规则对尾数进行舍入。常用的舍入方法在5.3.3节误差处理的讨论中作过介绍,运算时可根据具体情况选用。如无特殊要求我们在此约定: 本节对浮点运算结果的舍入处理均采用“0舍1入”法。 6) 溢出判断 规格化浮点数溢出的概念及其处理方法在讨论浮点数表示范围时曾作过介绍(见5.5.3节),一般以阶码是否溢出作为判断条件。浮点加减运算过程中有可能导致阶码上溢的操作是右规和舍入。由于右规过程中尾数右移一位时阶码加1,若阶码已为最大值再加1就会上溢。而在采用“0舍1入”法时,如果需要“入”则尾数末位加1。若尾数已达最大值,加1后会使尾数溢出,引起右规……接下来的情形就和右规时发生阶码上溢的情形一样了。因此当这两步操作进行时,需要及时地判溢出。注意,溢出判断操作不是在浮点加减运算结束时完成,而是在运算过程中需要的步骤立即进行。 3. 浮点加减运算举例 【例5.10】设X=2-1010×(-0.1010 1000),Y=2-1000×(+0.1110 1101),并设阶符2位,阶值4位,数符2位,尾值8位,均采用补码表示,求X±Y。 解: 由 X=2-1010×(-0.1010 1000),Y=2-1000×(+0.1110 1101) 得 [X]补=11,0110; 11.0101 1000≠0,[Y]补=11,1000; 00.1110 1101≠0 (1) 对阶。 [ΔE]补=[Ex]补-[Ey]补=11,0110+00,1000=11,1110 ΔE=-2,Ex<Ey,则[X]补的尾数右移2位,阶码加2,使Ex=Ey,即 [X]′补=11,1000;11.11010110 (2) 尾数相加减。 [Mx]′补+[My]补=11.11010110=00.11000011 +00.1110110100.11000011 [Mx]′补+[-My]补=11.11010110=10.11101001 +11.0001001110.11101001 即 [X+Y]补=11,1000; 00.1100 0011——已是规格化数 [X-Y]补=11,1000; 10.1110 1001——数符位=10,尾数溢出需右规 (3) 结果规格化。 右规后: [X-Y]补=11,1001; 11.0111 0100(1) 移出一位保护位,阶符=11,未溢出。 (4) 舍入处理。 采用“0舍1入”法,按照负数补码舍入规则,应舍,则 [X-Y]补=11,1001; 11.0111 0100 (5) 溢出判断。 本题在阶码可能发生溢出的(3)、(4)两步均未溢出,结果正确。 最后得[X+Y]补=1,1000; 0.1100 0011 [X-Y]补=1,1001; 1.0111 0100 对应的真值为X+Y=2-1000×(+0.1100 0011) X-Y=2-0111×(-0.1000 1100) 此例中浮点数的阶码和尾数都采用了补码表示,因此对阶和加减运算使用定点补码加减算法即可。若阶码用移码表示,则对阶时求阶差需要用到移码加减算法。移码加减运算规则将在讨论浮点乘除运算时介绍。 5.5.6规格化浮点乘除运算 与浮点加减运算不同,浮点乘除运算时不要求操作数的小数点对齐,阶码和尾数两部分可分别进行运算,运算过程中两者不发生关系。若两个浮点数相乘,阶码相加,尾数相乘; 两个浮点数相除,阶码相减,尾数相除。当然也需要考虑算后的结果规格化、舍入、判溢出,以及算前的判0等操作。因此,浮点乘除运算步骤一般需要考虑以下几步: (1) 0检测,判断操作数是否为0。 (2) 阶码运算,阶码相加(减),求乘积或商的阶码。 (3) 尾数运算,尾数相乘(除),求乘积或商的尾数。 (4) 结果规格化。 (5) 舍入。 (6) 溢出判断。 其中,(4)、(5)、(6)三步操作方法同浮点加减运算。 1. 移码加减运算 两个浮点数乘除的过程中,阶码需要进行加减运算。如果阶码用补码表示,则可按定点整数补码加减规则进行,这在前面我们已经介绍过。但是目前许多机器中使用移码来表示阶码,如IEEE 754标准采用阶移尾原的浮点数格式。这就对移码加减算法的探讨提出了要求。现在我们关心的是,两移码相加减能否直接得到和或差的移码?下面针对这一问题进行算法分析。 1) 算法推导 设两个k位的二进制整数Ex和Ey,其移码可定义为 [Ex]移=2k+Ex-2k≤Ex<2k [Ey]移=2k+Ey-2k≤Ey<2k 则 [Ex]移+[Ey]移=(2k+Ex)+(2k+Ey)=2k+[2k+(Ex+Ey)] =[Ex+Ey]移+2k(573) [Ex]移-[Ey]移=(2k+Ex)-(2k+Ey)=[2k +(Ex-Ey)]-2k =[Ex-Ey]移-2k(574) 可见直接用移码进行相加,得到的结果并非移码,而是比和(差)的移码增加(减少)了2k,需要对运算结果进行+2k(-2k)修正才能得到正确的移码。由于偏置常数2k正好是移码符号位的位权,因此修正的方法很简单,无论+2k还是-2k,都只需要将结果的符号位变反即可。尽管如此,仍然希望能有更加简便的算法可供使用。一种常用的改进算法是利用补码与移码符号位相反的简单转换关系,通过加减补码来实现移码加减运算。算法推导如下。 设同样位数的补码为: [Ey]补=2k+1+Ey(Mod 2k+1) 则 [Ex]移+[Ey]补=2k+Ex+2k+1+Ey=2k+1+2k+Ex+Ey =2k+Ex+Ey(Mod 2k+1) =[Ex+Ey]移(575) [Ex]移-[Ey]补=[Ex]移+[-Ey]补=2k+Ex+(2k+1-Ey) =2k+1+2k+Ex-Ey=2k+(Ex-Ey) (Mod 2k+1) =[Ex-Ey]移(576) 由上述推导结果可知,和或差的移码可通过移码与补码相加减直接获得。而运算前把移码转换为补码时,只要将其符号位变反即可。 2) 溢出判断 与补码加减运算一样,两个移码相加减结果也存在溢出出错的可能。那么移码运算又如何判断溢出呢?一种常用的方法是采用双符号位移码进行运算,但移码最高符号位的意义与变形补码的真符位有所不同。在此规定,无论正负移码的最高符号位(Es1)初始时均为0,而第二符号位(Es2)才表示移码的正负。因此运算开始前,移码两个符号位的组合含义为: Es1Es2=00——表示负数; Es1Es2=01——表示正数。 运算完成后,对Es1的取值进行判断,若Es1仍然为0,表示无溢出,两符号位的组合含义不变; 若Es1为1,则表示发生了溢出。进一步可以根据两个符号位的组合值来确定溢出的方向,此时若用移码表示阶码则有:  若Es1Es2=10,阶码正溢出(上溢),Es2由1破坏成0,溢出出错;  若Es1Es2=11,阶码负溢出(下溢),Es2由0破坏成1,看作机器0。 移码采用双符号位参加运算时,对应的补码也要用双符号位参加运算。 2. 浮点乘除基本规则 设两浮点数 X=Mx×RE,Y=My×RE,若求Zp=X×Y和Zq=X÷Y, 则浮点乘除运算的基本规则可描述为 Zp=X×Y=(Mx×My)×REx+Ey(577) Zq=X÷Y=(Mx÷My)×REx-Ey(578) 3. 浮点乘除运算步骤 现在,让我们进一步讨论浮点乘除运算每一步的具体操作方法。 1) 0操作数检测 运算前首先检测是否X=0?Y=0? 若X=0,则令Zp=0(乘法); 或Zq=0(除法),运算结束; 若Y=0,则令Zp=0(乘法); 或Zq=±∞(除法),此时也可视为运算异常,转非法除数处理,运算结束。 若X、Y均不为0,则可继续进行下一步运算。 2) 阶码相加减 若求X×Y,Ep=Ex+Ey 若求X÷Y,Eq=Ex-Ey 如果阶码用补码表示,就按定点整数补码加减算法及溢出判断规则进行运算; 若阶码用移码表示,则按移码加减算法和溢出判断规则进行运算。注意,阶码加减运算的结果有可能发生溢出,需要及时判断并转溢出处理。 3) 尾数相乘除 若求X×Y,Mp=Mx×My 若求X÷Y,Mq=Mx÷My 如果尾数用补码表示,按定点小数补码乘除算法进行运算; 如果尾数用原码表示,则要按定点小数原码乘除规则进行运算。有关算法(如加减交替除法)曾经在讨论定点乘除运算时介绍过(见5.3.4节、5.3.5节)。注意按照定点乘法算法求出的乘积是双倍长度的,超长部分应先予以保留,以备接下来的左规或舍入操作使用。由于接下来会对结果进行规格化处理,因此除法过程可不必先判溢出。为了提高商的精度,可多上几位商用作保护位。 4) 结果规格化 由于尾数是纯小数,相乘后结果不可能溢出,故不需右规。但乘积有可能变为非规格化数,此时需要左规。除法开始前若尾数满足M*x<M*y(M*x、M*y表示尾数的绝对值)的条件,结果不需右规,但可能需要左规; 如果不满足M*x<M*y的条件,则尾数会发生溢出,左右规都有可能需要进行。 5) 舍入处理 不论乘法还是除法,在规格化操作完成后,都需要对尾数剩余的保护位进行舍入处理。按照本教材的约定,舍入操作均采用0舍1入法实现。 6) 判断溢出 浮点乘除运算时溢出出错主要可能发生在阶码运算、结果规格化以及舍入处理等步骤,必须及时进行溢出判断,以免造成更大的错误。溢出判断方法与浮点加减运算相同,在此不再赘述。 4. 浮点乘除运算举例 为了使大家加深对浮点乘除算法的理解,下面举例说明其运算过程。 【例5.11】已知X=2-1001×(-0.1010 1001),Y=2+0101×(+0.1001 1111),假设浮点数采用阶移尾补格式,阶值4位,尾值8位,求Z=X×Y。 解: [X]阶移尾补=0,0111; 1.0101 0111≠0 [Y]阶移尾补=1,0101; 0.1001 1111≠0 (1) 阶码相加。 由于阶码用移码表示,因此采用移码加法较为方便。 [Ez]移=[Ex]移+[Ey]补=00,0111=00,1100,Es1=0,无溢出 +00,010100,1100 (2) 尾数相乘。 原则上讲可选任意一种定点补码乘法算法进行尾数运算,但为了加快运算速度,本题采用补码两位乘比较法。机器运算步骤同定点运算过程故省略。 [Mz]补=111.1001 0111 0000 1001 000 [Z]阶移尾补=00,1100; 111.1001 0111 0000 1001 000 (3) 结果规格化。 MsMMSB=11=0, 需要左规,即 [Z]阶移尾补=00,1011; 111.0010 1110 0001 0010 00 (4) 舍入处理。 取结果字长与原始操作数X、Y相同(单倍字长),采用0舍1入法,按负数补码的舍入规则,保护位的最高位为0,应“舍”,故 [Z]阶移尾补=00,1011; 111.0010 11100001 0010 00保护位 =00,1011; 111.0010 1110 (5) 溢出判断。 本题在阶码可能发生溢出的(1)、(4)两步均未溢出,结果正确。 最终结果为[Z]阶移尾补=0,1011; 1.0010 1110 Z=X×Y=2-0101×(-0.1101 0010) 【例5.12】用浮点除法计算29×-1932÷2-5×+2132,假设浮点数采用阶移尾补格式,阶值4位,尾值5位,求Z=X÷Y。 解: 这道题需要先把十进制操作数转换为规格化二进制真值形式,再进一步转换为阶移尾补的浮点规格化机器数格式,然后才可进行机器运算。 X=29×-193210=2+1001×(-0.10011)2≠0 Y=2-5×+213210=2-0101×(+0.10101)2≠0 [X]阶移尾补=1,1001,1.01101,[Y]阶移尾补=0,1011,0.10101 (1) 阶码相减。 采用移码减法进行运算 [Ez]移=[Ex]移+[-Ey]补=01,1001=01,1110,Es1=0,无溢出 +00,010101,1110 (2) 尾数相除。 采用补码加减交替除法,机器运算步骤同定点计算过程故省略。 [Mz]补=11.00011 [Z]阶移尾补=01,1110;11.00011 (3) 结果规格化。 商的双符号位为11,尾数无溢出,不需右规; MsMMSB=10=1,已是规格化数,不需左规。 (4) 舍入处理。 商的字长已与原始操作数X、Y相同,无保护位,不需舍入。 (5) 溢出判断。 本题在阶码可能发生溢出的(1)、(4)两步均未溢出,结果正确。 最终结果为 [Z]阶移尾补=1,1110; 1.00011 Z=X÷Y=2+1110×(-0.11101)2=214×-293210 5.5.7浮点运算的实现 1. 浮点运算器的基本配置 分析浮点四则运算算法可以发现,浮点运算分阶码运算和尾数运算两部分进行,阶码只需要加减运算,尾数则需要加、减、乘、除四则运算。由此可知浮点运算器可由两个定点运算部件组成,一个是阶码部件,用来完成阶码加、减以及对阶时求阶差、尾数右移次数的控制,规格化时阶码的调整等操作。另一个是尾数部件,用来完成尾数的四则运算以及舍入、结果规格化判断和溢出判断等操作。一个基本的浮点运算器框图如图551所示。 图551浮点运算器基本结构框图 图551示意出了由定点加减运算器配上阶差计数器E组成的阶码部件和由定点四则运算器实现的尾数部件,通过总线松散连接构成完整浮点运算部件的方式。虽然简单但基本上体现了浮点运算器的结构特点。 2. 具有高速乘除法器的浮点运算器 为了进一步提高乘除法运算速度,目前的浮点运算器中还经常设置阵列式的高速乘除法器,如图552所示。 图552设置有高速乘除法器的浮点运算器框图 图552示意的浮点运算器除了寄存器配置之外,阶码运算部分仍然由一个定点加减法器实现,而尾数运算部分则由一个定点加减法器和一个高速的定点乘除法器共同构成。这个浮点运算器的内部也采用了双总线连接方式,两条总线之间的传送则需要通过添加总线连接器来实现。 思考题与习题 1. 用十六进制写出大写字母“F”、小写字母“a”和星号“*”的ASCII码。当最高位用作偶校验位时,写出它们的ASCII机内码字节。 2. 汉字“大”和“小”的国标区位码分别为2083和4801,要求: (1) 分别写出这两个字对应的国标码; (2) 若采用汉字两个字节的最高位均设为“1”的机内表示方案,分别写出这两个字的机内码形式。 3. 用向量表示法,在32位字长的存储器中,用ASCII码分别按左→右(大端方式)和右→左(小端方式)的顺序表示下列字符串: (1) WHAT IS THIS? (2) THIS IS A DISK. 4. 用以下形式表示十进制数5862。 (1) 二进制数; (2) 8421码; (3) 余3码; (4) 2421码。 5. 用前分隔数字串表示法、后嵌入数字串表示法和压缩的十进制数串表示法表示下列十进制数,设存储器按字节编址。 +1980; -76543; +254; -1992 6. 有两位NBCD码编码的十进制整数置于寄存器A中,可以通过一个加法器网络将其直接转换成二进制整数。试用半加器、全加器电路画出该加法器网络。 7. 设X为整数,[X]补=1,X1X2X3X4X5,若要求X<-16,试问X1~X5应取何值? 8. 已知数的补码表示,求数的原码与真值。 [X1]补=0001 1010[X2]补=1001 1010[X3]补=1111 0001 9. 讨论若[X]补>[Y]补,是否有X>Y? 10. 设[X]补=a0.a1a2a3a4a5a6,其中ai取0或1,若要X>-0.5,求a0,a1,a2,…,a6的取值。 11. 当十六进制数9AH、80H和FFH分别表示原码、补码、反码、移码和无符号数时,对应的十进制真值各为多少(设机器数采用一位符号位)? 12. 设机器数字长为16位,写出下列各种情况下它能表示的数的范围。机器数采用一位符号位,答案均用十进制2的幂形式表示。 (1) 无符号整数; (2) 原码表示的定点小数; (3) 补码表示的定点小数; (4) 原码表示的定点整数; (5) 补码表示的定点整数。 13. 设机器字长为8位(含1位符号位),分整数和小数两种情况讨论真值X为何值时,[X]补=[X]原成立。 14. 设机器数字长为8位(含1位符号位),对下列各机器数算术左移一位、两位,算术右移一位、两位,并讨论结果是否正确。 [X1]原=0.001 1010;[X2]原=1.110 1000 [Y1]补=0.101 0100;[Y2]补=1.110 1000 [Z1]反=1.010 1111;[Z2]反=1.110 1000 15. 设有符号数[Y]原=[Y]反=[Y]补=1,011 0010,分别对这个8位字长的机器数进行算术左移1位、2位,算术右移1位、2位,逻辑左移1位、2位,逻辑右移1位、2位的操作,比较两种移位运算的区别,并分析结果的真值变化、误差及溢出情况。 16. 设X1=0.011 1000 010,Y1=-0.011 1000 010; X2=0.011 1001 100,Y2=-0.011 1001 100。 分别用原码和补码表示,如果只要求8位字长,请采用截断法、恒置1法和0舍1入法对每一个操作数进行舍入,并对舍入结果进行比较。 17. 设机器数字长为8位(含1位符号位),用补码加减运算规则计算下列各题,并指出是否溢出。 (1) X=-17/32,Y=19/64,求X-Y; (2) X=-21/32,Y=-67/128,求X+Y; (3) X=97,Y=-54,求X-Y; (4) X=118,Y=-36,求X+Y。 18. 用原码一位乘法和补码一位乘比较法、两位乘比较法计算X×Y。 (1) X=0.110 111,Y=-0.101 110 (2) X=-0.010 111,Y=-0.010 101 19. 用原码加减交替除法和补码加减交替除法计算X÷Y。 (1) X=-0.10101,Y=0.11011 (2) X=13/32,Y=-27/32 20. 设机器字长为16位(含1位符号位),若一次移位需1μs,一次加法需1μs,试问原码一位乘法、补码一位乘法、原码加减交替除法和补码加减交替除法最多各需多少时间? 21. 分别用8421码加法和余3码加法求57+48=?316+258,要求列出竖式计算过程。 22. 用预加6方案设计一位8421码加法单元,并以设计好的加法单元为模块。进一步设计一个4位的8421码加法器。 23. (1) 设计一个一位的余3码加法器,并分析其修正规律; (2) 用8位并行二进制加法器实现2位余3码加法,试提出你的方案。 24. 有下列16位字长的逻辑数(八进制表示): A=000 377; B=123 456; C=054 321 试计算: X1=(BC)·A; X2=/(/B·/C)+ A; X3=(AB)+/(A·C) 25. 设4位二进制加法器进位信号为C4C3C2C1,最低位进位输入为C0; 输入数据为A3A2A1A0和B3B2B1B0; 进位生成函数为g3g2g1g0,进位传递函数为p3p2p1p0; 请分别按下述两种方式写出C4C3C2C1的逻辑表达式: (1) 串行进位方式; (2) 并行进位方式。 26. 设机器字长为32位,用与非门和与或非门设计一个并行加法器(假设与非门的延迟时间为10ns,与或非门的延迟时间为15ns),要求完成32位加法时间不得超过0.2μs。画出进位线路逻辑框图及加法器逻辑框图。 27. 设机器字长为16位,分别按4、4、4、4和3、5、3、5分组后: (1) 画出两种分组方案的成组先行级联进位线路框图,并比较哪种方案运算速度快。 (2) 画出两种分组方案的二级先行进位线路框图,并对这两种方案的速度进行比较。 (3) 用74181和74182画出成组先行级联进位和二级先行进位的并行进位线路框图。 28. 假设某机字长为32位,加法器的输入数据为ai、bi,第1级进位函数为gi、pi,第2级进位函数为Gi、Pi,第3级进位函数为G*i、P*i,进位信号为Ci,其中i=0,1,2,…,从低位到高位递增。 (1) 请写出gi、pi的原理性逻辑表达式; (2) 假设第1级为4位分组,加法器采用二级先行级联进位方案,请写出C4、G0、P0的原理性逻辑表达式。 (3) 请用74181和74182为该机设计一个并行加法器。 29. 浮点数的格式为: 阶码6位(含1位阶符),尾数10位(含1位数符)。按下列要求分别写出正数和负数的表示范围,答案均用2的幂形式的十进制真值表示。 (1) 阶原尾原非规格化数; (2) 阶移尾补规格化数; (3) 按照(2)的格式,写出-27/1024和7.375的浮点机器数。 30. (1) 将十进制数138.75转换成32位的IEEE 754短浮点数格式,并用十六进制缩写表示。 (2) 将IEEE 754短浮点数C1B7 0000H转换成对应的十进制真值。 31. 设浮点数字长为32位,欲表示-6万~6万的十进制数,在保证数的最大精度条件下,除阶符、数符各取一位外,阶码和尾数各取几位?按这样分配,该浮点数溢出的条件是什么? 32. 对于尾数为40位的浮点数(不包括符号位在内),若采用不同的机器数表示,试问当尾数左规或右规时,最多移位次数各为多少? 33. 按机器补码浮点运算步骤计算[X±Y]补。 (1) X=2-011×0.101 100,Y=2-010×(-0.011 100) (2) X=2101×(-0.100 101),Y=2100×(-0.001 111) 34. 设浮点数阶码取3位,尾数取6位(均不包括符号位),要求阶码用移码运算,尾数用原码运算,计算X×Y和X÷Y,结果保留1倍字长。 (1) X=2100×0.100 111,Y=2011×(-0.101 011) (2) X=2101×(-0.101 101),Y=2001×(-0.111 100) 35. 设数的阶码3位,尾数6位,均不含符号位; 阶码用移码表示,尾数用补码表示; 阶的基为2。用浮点算法计算X+Y、X-Y、X×Y、X÷Y,结果要求为规格化数。已知: X=2-2×11/16; Y=23×(-15/16)。 36. 假定在一个8位字长的计算机中,定点整数用单字长表示,其中带符号整数用补码表示(1位符号位); 浮点数用双字长表示,阶码为8位移码(包括1位符号位),尾数用8位原码(包括1位符号位)。运行如下类 C 程序段: intx1=-124; intx2=116; unsigned int y1=x1; floatf1=x1; intz1=x1 + x2; intz2=x1 - x2; (1) 执行上述程序段后,所有变量的值在该计算机内的数据表示形式各是多少?所有变量的值对应的十进制形式各是多少? (2) 在该计算机中,无符号整数、有符号整数和规格化浮点数的表示范围各是什么?(要求: 用十进制2的幂形式表示) (3) 执行上述程序段后,哪些运算语句的执行结果发生了溢出?