来自:http://icebloods.blog.sohu.com/64118412.html
为叙述方便,先引进两个名词:机器数和真值。将一个数在机器中的表示形式,即编码称为机器数,将数本身称为真值。常用的机器数有三种:原码、补码和反码。
1.原码
1)通俗定义
将数的符号数码化,即用一个二进制位表示符号:对正数,该位取0,对负数,该位取1。而数值部分保持数的原有形式(有时需要在高位部分添几个0)。这样所得结果为该数的原码表示。
例,x=+1001010,y= -1001010,z= -1110(= -0001110)。当原码为8位时,x、y和z的原码分别是:
[x]原=01001010;
[y]原=11001010;
[Z]原=10001110.
其中最高位为符号位。
2)正规定义
其中,x为真值,n为原码的位数。这个定义实际是将真值的范围给出来了,当n=8时,-127<x<127,因而,其数值部分写成二进制形式,最多为7位。从该定义可看出,x为正数时,其原码还是数本身,第8位(符号位)补0;x为负数时,-x等于去掉负号,但要加上127,即第8位为1(127=10000000(2))。因此,这个定义和上面的通俗定义是一致的。
3)原码表示的特点
原码表示有三个主要特点:一是直观,与真值转换很方便;二是进行乘、除运算方便;三是加、减运算比较麻烦。第一点是显然的。说原码表示进行乘、除运算方便是因为其数值部分保持了数据的原有形式,对数值部分进行乘或除就可得到积或商的数值部分,而积或商的符号位可由两个数原码的符号位进行逻辑运算而得到。说原码表示进行加、减运算比较麻烦,以加法为例,两个数相加需先判别符号位,若其不同,实际要做减法,这时需再判断绝对值的大小,用绝对值大的数减绝对值小的数,最后还要决定结果的符号位。
2.补码
1)补码的引进和定义
据统计,在所有的运算中,加、减运算要占到80%以上,因此,能否方便地进行正、负数加、减运算,直接关系到计算机的运行效率。
如日常生活中的一个例子——指针式钟表。现在时针指向11点钟,要使其指向6点钟,有两种方法,一是正拨7个格,二是反拨5个格。如果把钟表看成一个计算器,正拨看成加运算,反拨看成减运算,那么,在钟表上有:11-5=11+7,即11+(-5)=11+7。之所以这样,是因为11+7=12+6,而在钟表上,12相当于0,超过12时,12就丢失了。这种运算称为按模运算。钟表的模为12。所谓“模”,是指一个系统的量程,或者说一个系统所能表示的最大的数(确切地说,为最大数时加1)。按模运算是指运算结果超过模时,模丢失。当模为整数时,按模运算也可理解成除以模求余数的过程。常用符号“mod”表示按模运算。
在计算机中,一个具体数据类型的位数是确定的。例如,字节型数据为8位,当每一位都为1时,再加1,最高位将产生进位。如果不采取措施,这个进位将被丢失,丢失的量为2^8=256,这就是8位数据的模。从上面的例子已看到,按模运算,可以使正数加负数转化成正数加正数(11-5=11+7),一个负数可以等价于一个正数(-5等价于+7)。看一下计算机中情况。例如,要将+0001111(15)和-0001100(-12)相加,实际是要做减法,但不这样做,而是先将-0001100与模10000000(256)相加,得11110100(-12+256=244),再拿原被加数0001111和它(11110100)相加,得00000011(15+244=256+3=3),最高位的进位,即模丢失。
这样,同样得到了正确结果。由此可见,在计算机中,只要将负数加模就可以转化成正数,使正数加负数转化成正数加正数。
把一个负数加模的结果称为该负数的补码(结果是一个正数,它和该负数是等价的,确切地说,是一对一的,因而可看作是该负数的编码),定义正数的补码就是它本身,符号位取0,即和原码相同。这就是补码的通俗定义。将这个定义用数学形式表示出来,就可得到补码的正规定义:
其中n为补码的位数。这个定义实际也将真值的范围给出来了,当n=8时,-127≤x<127。和原码相比,补码表示可多表示一个数。当n=8时,多表示的数是-127=-128。
2)补码的求法
对正数,补码同原码。例如,x=+0101001,[x]补=[x]原=00101001。对负数,由定义求补码,需做减法,不方便。经推导可知,负数的补码等于其原码除符号位外按位“求反”(1变0,0变1),末位再加1。例如,y=-0001100,[y]原=10001100,[Y]补=11110011+1=11110100。
多做几例,可得出一种心算求补的方法——从最低位开始至找到的第一个1均不变,符号位不变,这之间的各位“求反”(该方法仅用于做题)。
由求补的方法可以看出,对于补码,其符号位和原码的符号匣相同,也表示了真值的符号。
3)补码的性质
①[x+y]补=[x]补+[y]补,即两数之和的补码等于各自补码的和。
②[x-y]补=[x]补+[-y]补,即两数之差的补码等于被减数的补码与减数相反数的补码之和。
③[[x]补]补=[x]原,即按求补的方法,对[x]补再求补一次,结果等于[x]原。
4)利用补码进行加、减运算
引进补码的目的是方便带符号数的加、减运算,这里仅看一下加法,举几个例子。请注意:符号位也参与运算,符号位出现的进位为模,应丢弃。下面是三个利用补码求和的例子。这里假定机器数为8位。
符号位为0,真值为正,所以,x+Y,=+0001011(2)(+11)。
符号位有进位,自动丢失。符号位为1,真值为负,对[x+y]补求补得[x+Y]原=10001011,由此,x+Y= -0001011(-11)。
符号位有进位,自动丢失。符号位为O,真值为正,所以,x+Y=+0000111(+7)。
上面是三种类型的数的补码运算:正数+正数、负数+负数、正数+负数。负数+正数和正数+负数是一样的。由此可见,采用补码表示,进行数的加法运算可统一成进行数的补码加法运算。
上面的例子只是用来说明引进补码的好处,其运算过程不是计算机的实际过程。在计算机中不必每次都进行原码与补码之间的转换,可以将运算结果以补码形式存储起来,以便直接参与后面的运算。
3.反码简介
对正数,其反码与原码相同,也与补码相同。对负数,其反码等于原码除符号位外,按位求反(末位不加1)。利用反码也可使带符号数的加、减法转化为单纯的加法,但麻烦一些。一般把求反码作为求补的中间过程,即[x]补=[x]反+1。
上面所介绍的机器数编码主要用于汇编语言编程。在高级语言中,数可带有符号,但编译程序最终还是将其表示成机器数。
slowgrace注:在VB中,负数也是补码表示的。比如在立即窗口做如下测试:
?hex(clng(-1))
FFFFFFFF