电子计算机实质上是一个二进制的数字系统,在机器内部,二进制数总是存放在由具有两种相反状态的存储元件构成的寄存器或存储单元中,即二进制数码0和1是由存储元件的两种相反状态来表示的。另外,对于数的符号(正号“+”和负号“-”)也只能用这两种相反的状态来区别。也就是说,只能用0或1来表示。
数的符号在机器中的一种简单表示方法为:规定在数的前面设置一位符号位,正数符号位用0表示,负数符号位用1表示。这样,数的符号标识也就“数码化”了。即带符号数的数值和符号统一由数码形式(仅用0和1两种数字符号)来表示。例如,正二进制数 N 1 =+1011001,在计算机中表示为:
负二进制数 N 2 =-1011001,在计算机中表示为:
为了区别原来的数与它在机器中的表示形式,将一个数(连同符号)在机器中加以数码化后的表示形式,称为机器数,而把机器数所代表的实际值称为机器数的真值。例如,上面例子中的 N 1 =+1011001、 N 2 =-1011001为真值,它们在计算机中的表示01011001和11011001为机器数。
在将数的符号用数码(0或1)表示后,数值部分究竟是保留原来的形式,还是按一定规则做某些变化,这要取决于运算方法的需要。从而有机器数的3种常见形式,即原码、补码和反码。下面首先介绍机器数的这3种常见表示形式,然后介绍移码的特点及用途。
原码是一种比较直观的机器数表示形式。约定数码序列中的最高位为符号位,符号位为0表示该数为正数,为1表示该数为负数;其余有效数值部分则用二进制的绝对值表示。
例如:
在后面讨论定点数与浮点数表示时将会看到,定点数又有定点小数和定点整数之分,所以下面分别给出定点小数和定点整数的原码定义。
(1)若定点小数原码序列为 x 0 . x 1 x 2 … x n ,则
式中, x 代表真值,[ x ] 原 为原码表示的机器数。
例如:
x =+0.1011,则[ x ] 原 =0.1011;
x =-0.1011,则[ x ] 原 =1-(-0.1011)=1+0.1011=1.1011。
(2)若定点整数原码序列为 x 0 x 1 … x n ,则
例如:
x =+1011,则[ x ] 原 =01011;
x =-1011,则[ x ] 原 =2 4 -(-1011)=10000+1011=11011。
需要注意的是,在式(1-1)和式(1-2)中,有效数位是 n 位(即 x 1 ~ x n ),连同符号位是 n +1位。
对于原码表示,具有如下特点:
①原码表示中,真值0有两种表示形式。
以定点小数的原码表示为例:
[+0] 原 =0.00…0,[-0] 原 =1-(-0.00…0)=1+0.00…0=1.00…0
②在原码表示中,符号位不是数值的一部分,它仅是人为约定(“0为正,1为负”),所以符号位在运算过程中需要单独处理,不能当作数值的一部分直接参与运算。
原码表示简单直观,而且容易由其真值求得,相互转换也较方便。但计算机在用原码做加减运算时比较麻烦。例如当两个数相加时,如果是同号,则数值相加,符号不变;如果是异号,则数值部分实际上是相减,此时必须比较两个数绝对值的大小,才能确定谁减谁,并要确定结果的符号。这件事在手工计算时是容易解决的,但在计算机中,为了判断同号还是异号,比较绝对值的大小,就要增加机器的硬件设备,并增加机器的运行时间。为此,人们找到了更适合于计算机进行运算的其他机器数表示法。
为了理解补码的概念,我们先讨论一个日常生活中校正时钟的例子。假定时钟停在7点,而正确的时间为5点,要拨准时钟可以有两种不同的拨法,一种是倒拨2个格,即7-2=5(做减法);另一种是顺拨10个格,即7+10=12+5=5(做加法,钟面上12=0)。这里之所以顺拨(做加法)与倒拨(做减法)的结果相同,是由于钟面的容量有限,其刻度是十二进制,超过12以后又从0开始计数,自然丢失了12。此处12是溢出量,又称为模(mod)。这就表明,在舍掉进位的情况下,“从7中减去2”和“往7上加10”所得的结果是一样的。而2和10的和恰好等于模数12。我们把10称作-2对于模数12的补码。
计算机中的运算受一定字长的限制,它的运算部件与寄存器都有一定的位数,因而在运算过程中也会产生溢出量,所产生的溢出量实际上就是模。可见,计算机的运算也是一种有模运算。
在计算机中不单独设置减法器,而是通过采用补码表示法,把减去一个正数看成加上一个负数,并把该负数用补码表示,然后一律按加法运算规则进行计算。当然,在计算机中不是像上述时钟例子那样以12为模,在定点小数的补码表示中是以2为模。
下面分别给出定点小数与定点整数的补码定义:
(1)若定点小数的补码序列为 x 0 . x 1 … x n ,则
式中, x 代表真值,[ x ] 补 为补码表示的机器数。
例如:
x =+0.1011,则[ x ] 补 =0.1011;
x =-0.1011,则[ x ] 补 =2+(-0.1011)=10.0000-0.1011=1.0101。
(2)若定点整数的补码序列为 x 0 x 1 … x n ,则
例如:
x =+1011,则[ x ] 补 =01011;
x =-1011,则[ x ] 补 =2 5 +(-1011)=100000-1011=10101。
对于补码表示,具有如下特点:
①在补码表示中,最高位 x 0 (符号位)表示数的正负,虽然在形式上与原码表示相同,即“0为正,1为负”,但与原码表示不同的是,补码的符号位是数值的一部分,因此在补码运算中符号位像数值位一样直接参加运算。
②在补码表示中,真值0只有一种表示,即00…0。
另外,根据以上介绍的补码和原码的特点,容易发现由原码转换为补码的规律,即,当 x >0时,原码与补码的表示形式完全相同;当 x <0时,从原码转换为补码的变化规律为:“符号位保持不变(仍为1),其他各位求反,然后末位加1”,简称“求反加1”。
例如:
x =0.1010,则[ x ] 原 =0.1010,[ x ] 补 =0.1010
x =-0.1010,则[ x ] 原 =1.1010,[ x ] 补 =1.0110
容易看出,当 x <0时,若把[ x ] 补 除符号位外“求反加1”,即可得到[ x ] 原 。也就是说,对一个补码表示的数,再次求补,可得该数的原码。
反码与原码相比,两者的符号位一样。即对于正数,符号位为0;对于负数,符号位为1。但在数值部分,对于正数,反码的数值部分与原码按位相同;对于负数,反码的数值部分是原码的按位求反,反码也因此而得名。
与补码相比,正数的反码与补码表示形式相同;而负数的反码与补码的区别是末位少加一个1。因此不难由补码的定义推出反码的定义。
(1)若定点小数的反码序列为 x 0 . x 1 … x n ,则
式中, x 代表真值,[ x ] 反 为反码表示的机器数。
(2)若定点整数的反码序列为 x 0 x 1 … x n ,则
0在反码表示中有两种形式,例如,在定点小数的反码表示中:
[+0] 反 =0.00…0,[-0] 反 =1.11…1
如上所述,由原码表示容易得到相应的反码表示。
例如:
x=+ 0.1001,[ x ] 原 =0.1001,[ x ] 反 =0.1001
x=- 0.1001,[ x ] 原 =1.1001,[ x ] 反 =1.0110
如今,反码通常已不单独使用,而主要是作为求补码的一个中间步骤来使用。补码是现代计算机系统中表示负数的基本方法。
根据前面对原码、补码和反码各自特点的介绍和分析,现将真值、原码、补码和反码之间的相互转换规则汇总于图1.1中。
图1.1 真值、原码、补码和反码之间的转换
例如:
由于原码、补码、反码的大小顺序与其对应的真值大小顺序不是完全一致的,所以为了方便地比较数的大小(如浮点数的阶码比较),通常采用移码表示法,并常用来表示整数。它的定义如下:
设定点整数移码形式为 x 0 x 1 x 2 … x n ,则
[ x ] 移 =2 n + x -2 n ≤ x <2 n
式中, x 为真值,[ x ] 移 为其移码。
可见移码表示法实质上是把真值 x 在数轴上向正方向平移2 n 单位,移码也由此而得名。也可以说它是把真值 x 增加2 n ,所以又叫增码。
例如:
若 x =+1011,则[ x ] 移 =2 4 + x =10000+1011=11011
若 x =-1011,则[ x ] 移 =2 4 + x =10000-1011=00101
真值、移码和补码之间的关系如表1.1所示。
表1.1 真值、移码和补码对照表
从表1.1可以看到移码具有如下一些特点:
(1)移码是把真值映射到一个正数域(表中为0~255),因此移码的大小可以直观地反映真值的大小。无论是正数还是负数,用移码表示后,都可以按无符号数比较大小。真值与移码的映射如图1.2所示。
图1.2 真值与移码的映射图
(2)移码的数值部分与相应的补码各位相同,而符号位与补码相反。在移码中符号位为0表示真值为负数,符号位为1表示真值为正数。
(3)移码为全0时,它对应的真值最小。
(4)真值0在移码中的表示是唯一的,即:[±0] 移 =2 n ±000…0=1000…0。
(1)原码、补码、反码和移码均是计算机能识别的机器数,机器数与真值不同,它是一个数(连同符号)在计算机中加以数码化后的表示形式。
(2)正数的原码、补码和反码的表示形式相同,负数的原码、补码和反码各有不同的定义,它们的表示形式不同,相互之间可依据特定的规则进行转换。
(3)4种机器数形式的最高位 x 0 均为符号位。原码、补码和反码表示中, x 0 为0表示正数, x 0 为1表示负数;在移码表示中, x 0 为0表示负数, x 0 为1表示正数。
(4)原码、补码和反码既可用来表示浮点数(后面将介绍)中的尾数,又可用来表示其阶码;而移码则主要用来表示阶码。
(5)0在补码和移码表示中都是唯一的,0在原码和反码表示中都有两种不同的表示形式。
在数字系统和计算机中,按照对小数点处理方法的不同,数的表示可分为定点表示和浮点表示,用这两种方法表示的数分别称为定点数和浮点数。
定点表示法约定计算机中所有数的小数点位置固定不变。它又分为定点小数和定点整数两种形式。
1)定点小数
所谓定点小数是指:约定小数点固定在最高数值位之前、符号位之后,机器中所能表示的数为二进制纯小数,数 x 记作 x 0 . x 1 x 2 … x n ,其中 x i =0或1,0≤ i ≤ n ,其编码格式如下。
符号位 x 0 用来表示数的正负。小数点的位置是隐含约定的,机器硬件中并不需要用专门的电路来具体表示这个“小数点”。 x 1 x 2 … x n 是数值部分,也称尾数,尾数的最高位 x 1 称为最高数值位。
在正定点小数中,如果数值位的最后一位 x n 为1,前面各位都为0,则数 x 的值最小,即 x min =2 - n ;如果数值位全部为1,则数 x 的值最大,即 x max =1-2 - n 。
所以正定点小数 x 的表示范围为2 - n ≤ x ≤1-2 - n 。
2)定点整数
所谓定点整数是指:约定小数点固定在最低数值位之后,机器中所能表示的数为二进制纯整数,数 x 记作 x 0 x 1 x 2 … x n ,其中 x i =0或1,0≤ i ≤ n ,其编码格式如下。
在正定点整数中,如果数值位的最后一位 x n 为1,前面各位都为0,则数 x 的值最小,即 x min =1;如果数值位全部为1,则数 x 的值最大,即 x max =2 n -1。
所以正定点整数 x 的表示范围为1≤ x ≤2 n -1。
在实际的科学及工程计算中,经常会涉及各种大小不一的数。采用上述定点表示法,用划一的比例因子来处理,很难兼顾既要防止溢出又要保持数据的有效精度两方面的要求。为了协调数的表示范围与精度的关系,可以让小数点的位置随着比例因子的不同而在一定范围内自由浮动,这就是数的浮点表示法。
1)浮点数的编码格式
在浮点数的编码中,数据代码分为尾数和阶码两部分。尾数表示有效数字,阶码表示小数点的位置。加上符号位,浮点数通常表示为
N =(-1) S × M × R E
式中, M (mantissa)是浮点数的尾数, R (radix)是基数, E (exponent)是阶码, S (sign)是数据的符号位。在大多数计算机中,基数 R 取定为2,是个常数,在系统中是约定的,不需要用代码表示。数据编码中的尾数 M 用定点小数的形式表示,它决定了浮点数的表示精度。在计算机中,浮点数通常被表示成如下格式:
S 是符号位(1=尾数为负数,0=尾数为正数)
E 是阶码,占符号位之后的若干位。
M 是尾数,占阶码之后的若干位。
合理地分配阶码 E 和尾数 M 所占的位数是十分重要的,分配的原则是应使得二进制表示的浮点数既要有足够大的数值范围,又要有所要求的数值精度。
【 例1.16 】 设浮点数表示中, S =0, E =3, M =0.0100 2 ,试分别求出 R =2和 R =16时表示的数值。
解 根据浮点数的表示方法,当 R =2时,表示的数值为(-1) 0 ×0.0100×2 3 =2 3 ×1/4=2;当 R =16时,表示的数值为 N =(-1) 0 ×0.0100×16 3 =16 3 ×1/4=1024。
2)浮点数的规格化
为了使计算机在运算过程中不丢失有效数字,提高运算精度,通常都采用规格化的办法,使得尾数的绝对值保持在某个范围之内。
如果阶码以2为底,则规格化浮点数的尾数
M
的绝对值应满足:
。也就是说,当尾数用原码表示时,规格化浮点数的尾数最高位
M
1
=1;当尾数用补码表示时,对于正数,规格化浮点数的尾数最高位
M
1
=1;对于负数,规格化浮点数的尾数最高位
M
1
=0;即补码规格化浮点数的尾数有0.1××…×和1.0××…×(×表示0或1)两种形式。也就是说,对于补码,“尾数最高位与符号位相反”即为判断浮点数是否为规格化数的标志。
要使浮点数规格化,只要通过尾数的移位并相应调整阶码即可实现。尾数右移一位,阶码应加1,称为右规;尾数左移一位,阶码应减1,称为左规。
【 例1.17 】 将浮点数0.0011×2 0 和-0.0011×2 0 转换成规格化数表示。
解 数据0.0011×2 0 是正数,其符号位为0,在规格化时应将尾数左移2位,阶码减2,从而使小数点后第一位为1,规格化后为0.1100×2 -2 。
数据-0.0011×2 0 为负数,符号位为1,尾数的补码表示为1.1101,规格化时应将尾数左移2位,阶码减2,从而使小数点后第一位为0,规格化后表示为1.0100×2 -2 。
当一个浮点数的尾数为0时,不论它的阶码为何值,该浮点数的值都为0。当阶码的值为它能表示的最小值或更小的值时,不管其尾数为何值,计算机都把该浮点数看成0值,通常称其为机器0,此时该浮点数的所有位(包括阶码位和尾数位)都清为0值。
还需要说明的是,在计算机中,通常是以规格化浮点数的形式进行存储的,并对规格化浮点数进行运算。如果运算结果是非规格化的浮点数,则要进行规格化处理。也就是说,运算结果应在送存之前被规格化。
3)IEEE 754标准
虽然浮点数表示方式已被现代计算机系统普遍采用,但各种机器的表示方法很不一致,尾数长度、阶码长度和基值都有所不同,在发生一些特殊情况时缺乏对软件的支持。针对这种情况,IEEE(电气和电子工程师协会)对浮点数的编码格式进行了标准化,于1985年发布了IEEE 754标准。其目的是为了便于实现不同计算机之间的软件移植,并鼓励开发出优良的面向数值计算的程序。目前,大多数的微处理器和编译器都采用了这个标准。
IEEE 754标准定义的浮点数格式如图1.3所示。其中的浮点编码有32位、64位和80位3种格式,分别称为短实数(Short real)、长实数(Long real)和临时实数(Temporary real)。短实数又称为单精度浮点数,长实数称为双精度浮点数,临时实数也称为扩展精度浮点数。
在IEEE 754浮点数格式中,符号位 S 仍然用0表示正数,1表示负数。对于32位格式,阶码为8位,正常数的阶码 E 的取值范围为1~254,偏移值为127;尾数 M 可以取任意的23位二进制数值,加上隐含的 M 0 (=1)位,可达到24位的运算精度。这样,32位的单精度数代码所对应的数值公式为
(-1) S ×1. M ×2 E -127
IEEE 754标准的浮点数一般都表示成规格化的形式。如上式所示,在IEEE 754标准的规格化浮点数表示中,其尾数的最高位 M 0 总是1,且它和小数点一样隐含存在,在机器中并不明确表示出来,只需在数值转换时在公式中加上这个1即可。
阶码 E 是一个带偏移的无符号整数,从中减去相应的偏移值即为浮点数的实际阶码值。对于单精度的浮点数而言,由于阶码 E 的偏移值为127,所以,阶码 E 的1~254的取值范围所表示的实际阶码值为-126~+127(1-127=-126,254-127=127)。而对于双精度浮点数格式,阶码取值范围为1~2046,偏移值为1023,所表示的实际阶码值为-1022~+1023(1-1023=-1022,2046-1023=1023)。64位的双精度数代码所对应的数值公式为
(-1) S ×1. M ×2 E -1023
图1.3 IEEE 754浮点数格式
【 例1.18 】 试写出十进制数-0.625的IEEE 754单精度数标准代码。
解 先将-0.625转换为二进制形式为-0.101,相应的浮点数表示形式为-0.101×2 0 ;再转换为IEEE 754标准的规格化形式为-1.01×2 -1 。
根据IEEE 754单精度数的数值公式:(-1) S ×1. M ×2 E -127 ,十进制数-0.625可表示为
可见, E =126=(01111110) 2 。
所以,-0.625的IEEE 754单精度数标准代码为
【 例1.19 】 试给出如下IEEE 754单精度标准代码的十进制数表示。
解 符号位 S =0,阶码 E =(10000011) 2 =(131) 10 ,规格化的尾数=(1.1) 2 ,根据IEEE 754单精度标准的数值公式,可得所求十进制数为
(-1) 0 ×(1+0.5)×2 131 - 127 =1.5×2 4 =1.5×16=24.0
此外,在IEEE 754标准中,还对浮点数运算中的一些特殊的情况做了完整定义,定义了一些特殊的数据格式,以处理上溢、下溢等异常情况。阶码中保留了一些值(如全1和全0)用于表示这种特殊的数据,包括∞和0。
IEEE 754标准还可以表示“非数”NaN(Not a Number),当阶码为全1、尾数不是0时,就表示NaN。NaN可以用来通知一些异常条件。
可以看出,IEEE 754这种浮点表示方法可以提高整个计算机的性能,提高计算的可靠性和有效性,减少特殊情况下的软件处理工作量。
人们最熟悉、最习惯的是十进制计数系统,而在数字设备和计算机内部,数是用二进制表示的。为了解决这一矛盾,可把十进制数的每位数字用若干位二进制数码来表示。通常称这种用若干位二进制数码来表示一位十进制数的方法为二-十进制编码,简称BCD码(Binary Coded Decimal)。二-十进制编码具有二进制编码的形式,这就满足了计算机内部需采用二进制的要求,同时又保持了十进制数的特点。它可以作为人与计算机联系时的一种中间表示,而且计算机也可以对这种形式表示的数直接进行运算。
按照BCD码在计算机中的处理和存储形式,又有压缩BCD码(Packed BCD Data)及非压缩BCD码(Unpacked BCD Data),也分别称为组合BCD码和非组合BCD码。在组合BCD码中,十进制数字串以4位一组的序列进行存储,每个字节(8位)存放两个十进制数字,一个十进制数字占半个字节(4位)。例如,十进制数9502的存储形式如下:
在非组合BCD码中,每个十进制数字存储在8位字节的低4位,高4位的内容无关紧要。也就是说,每个字节只存储一个十进制数字。在此种格式中,十进制数9502需占4个字节,其存储形式如下:
其中 u 表示任意(既可为1,也可为0)。
8421码是最基本最常见的一种二-十进制编码形式,也称8421BCD码。它是将十进制数的每个数字符号用4位二进制数码来表示,每位都有固定的权值。因此,称它为有权码或加权码(Weighted Code)。8421码各位的权值从高位到低位依次为 W 3 =2 3 =8, W 2 =2 2 =4, W 1 =2 1 =2, W 0 =2 0 =1,所以,与4位二进制数 b 3 b 2 b 1 b 0 相对应的1位十进制数 D 可以表示为
D= 8 b 3 +4 b 2 +2 b 1 + b 0
表1.2列出了十进制数字与8421码的对应关系。
表1.2 十进制数字与8421码的对应关系
从表1.2可见,用8421码表示的每个十进制数字与用普通二进制表示的完全一样。或者说,每个十进制数字所对应的二进制代码,就是与该十进制数字等值的二进制数。因此,在8421码中,有6种代码(1010,1011,1100,1101,1110,1111)是不可能出现的,也称它们为非法的8421码。
任何一个十进制数要写成8421码表示时,只要把该十进制数的各位数字分别转换成对应的8421码即可。如(253) 10 =(001001010011) 8421 。
反过来,任何一个8421码表示的十进制数,也可以方便地转换成普通的十进制数形式。如(0101011110010001) 8421 =(5791) 10 。