您的位置:首页 > 其它

原码、反码、补码、移码 终极总结

2012-12-07 19:00 399 查看
原码、反码、补码、移码  终极总结
全文分析案例中假设机器字长为8位,即编码总位数为8
 
0、 二进制基础

1字节 = 8位,所以它能表示的最大数当然是8位都是1

即1字节的二进制数中,最大的数:1111 1111

(1111 1111)B = 28 – 1  =  255  =  MAX

无论是什么进制,都是左边是高位,右边是低位。

1个字节有8位,可以表达的最大的数是255,也就是说表示0~255这256个数。

那么两个字节(双字节数)呢?双字节共16位。 1111111111111111,这个数并不大,但长得有点眼晕,从现在起,我们要学会这样来表达二制数:

1111 1111 1111 1111,即每4位隔一空格。

双字节数最大值为

1 * 215 + 1 *214 + 1* 213 + 1 * 212 + 1 * 211 + 1
* 210 + …… + 1 * 22 + 1 * 21 + 1* 20 = 65535

 

1、机器数、无符号数、有符号数

在计算机中既可以使用无符号数也可以使用带符号数,由于计算机仅“认得”二进制,所以在计算机内部所有信息二进制数串形式表示的。故带符号数的符号也必须二进制化。即用0、1来表示。规定用最高位来表示数的符号:‘0’表示正号、‘1’表示负号。一个在机器(计算机)中的表示形式称为该数的机器数。反之,一个机器数所表示的那个数的本身称该机器数的真值。而将一个真值表示成二进制字串的机器数的过程就称为编码。

无符号数和它的机器数在表示形式上是完全一致的,其特点是每一个二进制位均表示数值。

 

无符号数没有原码、反码和补码一说。只有带符号数才存在不同的编码方式。

 

2、无符号数和有符号数的范围区别

无符号数中,所有的位都用于直接表示该值的大小。有符号数中最高位用于表示正负,所以,当为正值时,该数的最大值就会变小。我们举一个字节的数值对比:

无符号数: 1111 1111  值:255 1* 27 + 1*
26 + 1* 25 + 1* 24 + 1* 23 + 1* 22 + 1* 21 + 1* 20

有符号数: 0111 1111  值:127        1* 26 +
1* 25 + 1* 24 + 1* 23 + 1* 22 + 1* 21 + 1* 20

 

同样是一个字节,无符号数的最大值是255,而有符号数因其最高位被挪去表示符号而导致最大表示值缩水为:127。不过,有符号数的长处是它可以表示负数。因此,虽然它的在最大值缩水了,却在负值的方向出现了伸展。我们仍一个字节的数值对比:

无符号数:        0--------------------------255

有符号数:        -128 --------- 0 ----------127

同样是一个字节,无符号的最小值是0,而有符号数的最小值是-128。所以二者能表达的不同的数值的个数都一样是256个。只不过前者表达的是0到255这256个数,后者表达的是-128到+127这256个数。

 

3、带符号数在计算机中原码、反码、补码和移码的表示法

3.1 原码表示法

最高位表示符号(“0”表示正数,“1”表示负数),其余位表示数值。如

[ +8 ]原 = 0
000 1000
 [ -8 ]原 = 1000 1000

[注] 红色表示符号位蓝色表示数值位

 

3.2反码表示法

正数的反码与其原码相同,如[ +8 ]反 = [ +8 ]原 = 0000 1000

负数的反码是将其原码的数值位按位取反符号位不变,如[ -8 ]反 =1111 0111

 

3.3 补码表示法

正数的补码与其原码相同,如[ +8 ]补 = [ +8 ]反 = [ +8 ]原 =
0 000 1000


负数的补码是将其反码在末位上加1,即得所求。如[ -8 ]补 = 1111 1000

 
采用补码的两个原因

[1]   引入补码的原因是为了用加法代替减法,因为使用补码可以将符号位和其他位统一处理。通常,在计算机内部用补码来表示符号数。

[2]   两个用补码表示的数相加时,如果最高位(符号位)有进位,则进位被舍弃。

 

补码运算有两个好处

[1]   使符号位能与有效值部分一起参加运算,从而简化运算规则。从而可以简化运算器的结构,提高运算速度;(减法运算可以用加法运算表示出来)

[2]   加法运算比减法运算更易于实现。使减法运算转换为加法运算,进一步简化计算机中运算器的线路设计。

 

下面深入分析上面所陈述的采用补码的原因(目的)。

用带符号位的原码进行乘除运算时结果正确,而在加减运算的时候就出现了问题,如下:假设字长为8bits

( 1 ) 10(1)10 = (1 )10 + ( -1
)10= ( 0 )10

(00000001)原 + (10000001)原= (10000010)原
= ( -2 ) 显然不正确.。

因为在两个整数的加法运算中是没有问题的,于是就发现问题出现在带符号位的负数身上,对除符号位外的其余各位逐位取反就产生了反码。反码的取值空间和原码相同且一一对应。

反码的减法运算:

( 1 ) 10(1)10 = (1 )10 + ( -1
)10= ( 0 )10

(00000001) 反+ (11111110)反 = (11111111)反=
( -0 ) 有问题。

( 1 )10 - ( 2)10 = (1 )10 + ( -2 )10 = ( -1 )10

(00000001) 反+ (11111101)反 = (11111110)反=
( -1 ) 正确

问题出现在(+0)和(-0)上,在人们的计算概念中零是没有正负之分的。

于是就引入了补码概念。负数的补码就是对反码加1,而正数不变,正数的原码反码补码是一样的。在补码中用(-128)代替了(-0),所以补码的表示范围为:(-128~0~127)共256个。

[](-128)没有相对应的原码和反码(-128)
= (10000000)


补码的加减运算如下:

( 1 ) 10(1)10 = (1 )10 + ( -1
)10= ( 0 )10

(00000001)补 + (11111111)补= (00000000)补
= ( 0 ) 正确

( 1 )10 - ( 2)10 = (1 )10 + ( -2 )10 = ( -1 )10

(00000001) 补+ (11111110)补= (11111111)补
= ( -1 )正确

采用补码表示还有另外一个原因,那就是为了防止0的机器数有两个编码。原码和反码表示的0有两种形式+0和-0,而我们知道,+0和-0是相同的。这样,8位的原码和反码表示的整数的范围就是-127~+127(11111111~01111111),而采用补码表示的时候,00000000是+0,即010000000不再是-0,而是-128,这样,补码表示的数的范围就是-128~+127了,不但增加了一个数得表示范围,而且还保证了0编码的唯一性。

 

补码表示法小结

补码表示范围是 -128127.
根据补码的几条规定即可推出上述结论:
1 若二进制每位全为0,则表示数0
2 若最高位(即符号位)为0,表示正数
3 若最高位为1,表示是负数,而该负数的绝对值是多少呢?将每个二进制位(包括符号位)取反加1,得到一个二进制数,将该数看成无符号数,其值就是上述负数的绝对值
[]二进制的 10000000的最高位为1, 所以它表示的是负数。是负的多少呢?我们将其八位全部取反,得到01111111, 然后加1,得到10000000.将该数看作无符号数,值为128,
故计算机中的10000000表示的是-128
由于“编码总位数为8”的限制,真值 -128无法用原码、反码来表示(如果要表示就要用9位才行,如 110000000  [红色为符号位,蓝色为数值位]),似乎不能用上述规则来求解补码,但实际上是可行的——只要不管它的最高位即可,操作办法如下:

128化为二进制为:1 0000000,最高位为1,可以只对舍去最高位后剩余的7位进行处理即可,首先取反得:1111111,加1得:1 0000000,最高位有进位需丢弃,即得:0000000,加上符号位就得补码:1
0000000


最高位(即符号位)为1的8位有符号数有128个,故可表示128个负数;最高位为0的8位有符号数有128个,但全0的那个表示数0,所以总共只能表示127个正整数。
所以补码可以表示 128个负数 + 一个0 +127个正数 =256 个数。
 

3.3.1由补码求其真值的方法

先看[X]补的最高位,若为‘0’,说明X为正数,且其[X]补的其余位即X的数值;如为‘1’,说明X为负数,其数值应通过将[X]补的其余位按位取反,然后末位加1的方法得到。

[例1] 已知[X]补 = 0111 1000,求X的真值。

[解 ]  由于最高位为0,故X为正,数值为111 1000 , 所以 X = +120

[例2] 已知[X]补= 1011 0010 ,求X的真值。

[解 ]  由于最高位为1,故X为负,将[X]补的其余位011 0010 逐位取反且末位加1,便得到X的数值100 1110,所以 X = -78。

 

3.3.2 “溢出”的判断方法

8位二进制补码所能表示的带符号数的范围是 -128 至 +127,当运算结果超出了这一范围时,将会出错。这种出错在计算机术语中称之为“溢出”。在计算机中,“溢出”的判断是由下面的逻辑表达式来实现的(设采用n位二进制补码进行运算):

OF = CYn⊕CYn-1
其中,OF是“溢出”标志位,为1表示溢出;CYn是最高位的进位(第n位向第n+1位的进位);CYn-1是次高位的进位(第n-1位向第n位的进位)。是异或逻辑运算符,左右两值相同为假,不同为真。

 

3.3.3求补运算方法

所谓“求补”就是将补码的每一位(包括符号位)逐位取反,末尾加1。

应用公式:

[  [ X ]补]求补 = [ -X ]补
[][ [+8]补 ]求补 = [ -8 ]补

即 [ [0000 1000]补 ]求补 = [ 1111 1000 ]补

[]有一个方法可以快速进行求补运算,从当前补码右边数起,直到第一个1(包括其自身)之间的位值不变,其余位求反就是结果。

[] [+8]补 =0000 1000 从当前补码右边数起,直到遇到第一个1(这里我们用红色标出来了)为止,那么从右边数过来直达这个1(包括其自身)之间的位值(本例中为1000不变其余位求反,就是[
[+8]补 ]求补
的结果:11111000

 

3.4 移码表示法

移码(又叫增码)是符号位取反的补码,一般用做浮点数的阶码,引入的目的是为了保证浮点数的机器零为全0

移码的定义:设由1位符号位和n位数值位组成的阶码,则 [X]移=2En + X -2n≤X ≤ 2n

  例如: X= +1011

           [X]移=11011 符号位“1”表示正号

         X = -1011

           [X]移=00101 符号位“0”表示负号

移码与补码的关系: [X]移与[X]补的关系是符号位互为相反数仅符号位不同),

  例如:X= +1011

          [X]补=01011

          [X]移=11011

    X = -1011

          [X]补=10101

          [X]移=00101

 

参考来源

[1] http://blog.csdn.net/nyhuachen/article/details/6424736

[2] http://foryou11.blog.163.com/blog/static/178378113201151482136735/

[3] http://blog.163.com/ac_victory/blog/static/10331872620097262409141/?fromdm&fromSearch&isFromSearchEngine=yes

[4] http://leochal.blog.163.com/blog/static/2760656420083232331362/?fromdm&fromSearch&isFromSearchEngine=yes

[5] http://blog.csdn.net/studyvcmfc/article/details/7603555

[6] http://www.cnblogs.com/acheng99/archive/2009/09/02/1559037.html

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: