现实生活中的数值数据主要分整数和实数两类,在计算机中整数用定点数表示,实数用浮点数表示。因为所有带符号整型数都用补码表示,所以,高级语言程序中的所有整数算术运算在计算机中都是一种补码运算。目前通用计算机中的浮点数多采用IEEE 754标准,其中的尾数用定点原码表示,因此浮点数算术运算的实现中涉及到原码的加、减、乘、除运算。

一、定点数的表示和运算

1 定点数的表示

计算机中的定点整数分无符号整数和带(有)符号整数。

无符号整数指一个编码的所有二进位都用来表示数值而没有符号位,即默认数的符号为正,所以无符号整数就是正整数或非负整数。通常把无符号整数简单地说成无符号数。

带符号整数也被称为有符号整数,它必须用一个二进位来表示符号。目前所有计算机中都用补码表示带符号整数。n位带符号整数可表示的数值范围为–2n-1 ~(2n-1–1)。例如,8位带符号整数的表示范围为–128 ~ +127。与原码相比,补码表示不对称,它可以多表示一个最小负数,其形式为10…0,-1的补码形式为11…1。

2 定点数的运算

计算机完成的功能通过执行程序来实现,任何程序最终都要转换为机器指令。指令中包含的各种算术逻辑运算能直接在硬件上执行。高级语言中支持的定点整数运算包括移位、加、减、乘、除等基本类型。因为计算机中运算电路宽度有限,所以在运算过程中可能会发生高位数据丢失的问题,因此,真正的运算结果可能会超出运算电路的宽度从而造成结果溢出。

(1)移位操作

移位操作有逻辑移位和算术移位两种。逻辑移位不考虑符号位,总是把高(低)位移出,低(高)位补0。对于带符号整数的移位操作应采用补码算术移位方式,左移时,高位移出,低位补0;右移时,低位移出,高位补符号。

左移一位表示扩大一倍,左移k位,表示乘以2k。因此左移可能发生溢出。右移一位表示缩小一倍,右移k位,表示除以2k。

(2)补码加/减运算

对于两个补码表示的n位定点整数X和Y,X+Y和X–Y的运算电路如图1所示。

最终运算结果的高位丢弃,保留低n位,相当于对和取模2n 。当控制端Sub为1时,做减法,实现F=X–Y;当控制端Sub为0时,做加法,实现F=X+Y。

因为无符号整数相当于正整数,而正整数的补码表示等于其二进制表示本身,所以,无符号整数的二进制表示相当于正整数的补码表示,因此,该电路同时也能实现无符号整数的加/减运算,可通过标志信息对运算结果进行不同的解释。

零标志ZF=1表示不管是当成无符号数还是带符号整数来运算,结果都为0;

溢出标志OF=1表示当作为带符号整数运算时,结果发生了溢出。因为两个同号数相加其结果的符号一定同两个加数的符号,所以,当X和Y’的最高位相同且不同于结果的最高位时,使OF=1,否则OF=0。对于无符号整数运算,OF没有意义。

符号标志SF表示结果的符号,即F的最高位。对于无符号整数运算,SF没有意义。

进/借位CF表示无符号数加/减运算时的进位/借位。加法时,若CF=1表示无符号数加法溢出;减法时若CF=1表示不够减。因此,加法时CF就应等于进位输出C;减法时,就应将进位输出C取反来作为借位标志。综合起来,可得CF=Sub⊕C。对于带符号整数运算,CF没有意义。

(3)原码加/减运算

原码加减运算需要比较两个操作数的符号,对加法实行“同号求和,异号求差”,对减法实行“异号求和,同号求差”。原码运算电路是在图2-2所示电路的基础上加上一些附加电路而构成。

(4)定点数乘法运算

原码乘法时,符号位与数值位分开计算,因此,原码乘法运算分为两步。①确定乘积的符号位,由两个乘数的符号异或得到。②计算乘积的数值位。即执行无符号数乘法运算。补码乘法时,符号位可以和数值部分一起进行运算。

因为乘法运算是通过若干次加和移位实现的,所以,在计算机中只要通过控制加法器和移位器进行若干次操作就可以实现乘法运算,因此乘法指令比加法和移位等运算指令的执行时间长,需要很多时钟周期才能完成一次乘法指令。

为了加快乘法运算,有些处理器中会使用专门的乘法器来实现,如阵列乘法器,也可以通过流水线处理方式加快乘法运算速度。这种情况下,可以在很少的时钟周期内完成一次乘法运算。

(5)定点数除法运算

原码除法时,符号位与数值位分开计算,因此,原码除法运算分为两步。①确定商的符号位,由两个数的符号异或得到。②两个数的数值部分按无符号数除法运算。补码除法时,符号位可以和数值部分一起进行运算。

在计算机中通过控制ALU做加/减和移位操作来实现除法运算,因此除法指令比加法、减法、移位等操作指令的执行时间长,而且不能进行流水处理,需要很多时钟周期才能完成一次除法操作。为了加快除法运算,也可以使用专门的除法器来实现除法运算。

对于整数除运算,如果除数为0,则结果无法表示,此时除法指令的执行会发生异常。

(6)溢出的概念及其判断

定点运算结果是否溢出,主要看结果是否可用给定长度的机器数表示。计算机中的带符号整数都用补码表示,因而带符号整数的机器数按补码规则进行判断。

a)移位操作:无符号数左移(逻辑左移)一位时,如果最高位移出的是1,则发生溢出。带符号整数左移(算术左移)一位时,如果移出的高位不同于移位后的符号位,即左移前、后符号位不同,则发生溢出。右移操作不会发生溢出。

b)加减操作:对于n位无符号数加运算,如果相加后结果的位数超过n位,即最高位有进位,则溢出;对于无符号数减运算,如果被减数小于减数,则结果溢出。对于带符号数加/减运算,如果OF=1,则结果溢出,否则不溢出。

c)乘法操作:对于两个n位无符号数乘运算,如果结果取2n位,则不会溢出;如果结果取n位,则丢弃的高n位若全为0,则不溢出,否则溢出。对于两个n位带符号整数乘运算,如果结果取2n位,则不会溢出;如果结果取n位,则丢弃的高n位若全部都与低n位的最高一位相同,则不溢出,否则溢出。

d)除法操作:对于两个n位无符号整数除运算,结果肯定不会溢出。对于两个n位带符号整数除运算,只有当被除数是n位最小整数-2n-1(机器数为10…0)而除数是-1(机器数为10…0)时,才会发生溢出,否则不会溢出。

二、浮点数的表示与运算

目前几乎所有计算机都采用IEEE 754标准表示浮点数。浮点数运算仅包括基本的加、减、乘和除等算术运算,而不用考虑移位和各类逻辑运算。

1 浮点数的表示

IEEE 754标准中,提供了两种基本浮点格式:32位单精度和64位双精度格式。32位单精度格式中包含1位符号s、8位阶码e和23位尾数f;64位双精度格式包含1位符号s、11位阶码e和52位尾数f。其基数隐含为2;尾数用原码表示,第一位总为1,因而可在尾数中缺省第一位的1,称为隐藏位,使得单精度格式的23位尾数实际上表示了24位有效数字,双精度格式的52位尾数实际上表示了53位有效数字。IEEE 754规定隐藏位“1”的位置在小数点之前。

对于阶码范围在1~254(单精度)和1~2046 (双精度)的数,是一个正常的规格化非0数。根据IEEE 754的定义,这种数的阶(指数)的范围应该是–126~+127(单精度)和–1022~+1023(双精度),其值的计算公式分别为:

(–1)s ×1.f × 2e-127   和 (–1) s×1.f × 2e-1023

阶码为全0或全1的特殊位序列有其特别的解释。(1)全0阶码全0尾数:表示+0/–0,零的符号取决于符号位s。(2)全0阶码非0尾数:表示非规格化数,其隐藏位为0,单精度和双精度浮点数的阶分别为–126或–1022。(3)全1阶码全0尾数:表示+∞/–∞,无穷大数既可作为操作数,也可能是运算的结果。例如,浮点除运算5.0/0=+∞。(4)全1阶码非0尾数:表示NaN (Not a Number),NaN表示一个没有定义的数,称为非数。例如,浮点除运算0.0/0.0=NaN。

2 浮点数的运算

计算机中的浮点数表示类似于现实中的科学计数法,因此,两者的运算方法也类似。

(1) 浮点数的加减运算

包括对阶、尾数加减、规格化和舍入4个步骤,此外,还需进行溢出判断和处理。在对阶和尾数右规时,可能会对尾数进行右移,为保证运算精度,一般将低位移出的位保留下来,参加中间过程的运算,最后再将运算结果进行舍入,以表示成IEEE 754格式。IEEE 754标准规定,中间结果右边必须至少额外保留两位附加位:警戒位(guard)和舍入位(round)。IEEE 754的默认舍入方式为就近舍入到偶数:当运算结果是两个可表示数的非中间值时,采用“0舍1入”方式;当运算结果正好在两个可表示数中间时,结果强迫为偶数。

(2) 浮点数的乘除运算

与科学计数法的乘除运算一样:“尾数相乘、除,阶码相加、减”。运算结果需要进行规格化、舍入和判断溢出。

(3) 浮点数运算的溢出判断和处理

对于IEEE 754标准,在运算前要先将隐含的“1”作为尾数的一部分进行处理。不管是加减运算还是乘除运算,在运算的最后都要进行规格化、舍入和溢出判断。当尾数中有效数字进入到小数点前面两位时,发生尾数溢出。此时,运算结果并不一定发生溢出,需要对尾数进行右规。

在进行尾数规格化和尾数舍入时,可能会对结果的阶码执行加、减运算。因此,必须考虑结果的阶码溢出问题。若一个正的阶(正指数)超过了最大允许值(127或1023),则发生“阶码上溢”,机器产生“阶码上溢”异常,也有的机器把结果置为“+∞”(数符为0时)或“–∞”(数符为1时)后,继续执行下去,而不产生“溢出”异常。若一个负的阶(负指数)超过了最小允许值(–126或–1022),则发生“阶码下溢”,此时,一般把结果置为“+0” (数符为0时)或“– 0”(数符为1时),也有的机器引起“阶码下溢”异常。