原码、反码和补码——整数运算

下文以8位整数为例,第一位表示符号位,0为正,1为负

编码说明

    所有整数的原码、反码、补码都相同。负数的反码和补码的符号位都不改变,反码其它位求反,补码其它位求反后再加1。同一个二进制数在不同编码中的解释可能不同,一般来说,0开头的8位数据在三种编码中解释相同,而以1开头的则解释不同

[+1]=0000 0001,[+1]=0000 0001,[+1]=0000 0001

[-1]=1000 0001,[-1]=1111 1110,[-1]=1111 1111

    原码表示的范围是[-127~-0,+0~+127],反码的范围和原码一致,补码的范围是[-128~0~+127],不同之处在于 1000 0000 在原码中是-0,而在补码中规定是-128,

[-127]+[-1]=[1000 0001]+[1111 1111]=[1000 0000]

[+127]+[+1]=[0111 1111]+[0000 0001]=[1000 0000]

符号位是1,所以就规定成-128。[0]=[+1]+[-1]=[0000 0001]+[1111 1111]=[0000 0000]

整数运算的问题

    所有整数运算全部可以化为加法,包括正正加,正负加,负负加,用原码计算,正正结果一般是正确的,但是会有溢出,负负会把符号位加成0,而正负则结果根本就不对,例如

[+2]+[-1]= 0000 0010+1000 0001 = 1000 0011 = [-3]

结果错误了,原因是符域和值域是分开计算的,要想一个办法让他们一起参与运算。

补码的来历

    我们考虑这样一种运算,f(x)= x mod 2^n,这个运算我们总能保证f(x)的值不超过2^n,特别对于x如果是二进制数,这个运算会非常简单,我们只要保留x的最低n位即可,函数f就可以理解为取x的最低n位,加法运算可以保证封闭性,利用这个式子

f(x+y)=f(f(x)+f(y))

我们现在需要确定的是,给定x>0,f(-x)=?,就是负数的映射方式,根据f定义容易知道f(-x)=-f(x),而f(x)-f(x)=0,所以f(x)+f(-x)=0,上文我们强调我们所有的加法最终结果都要求f,即保证结果不超过2^n,所以f(x)+f(-x)=2^n也满足我们的要求(和的最高位1被扔掉了),给定f(x),求f(-x)的方法实际就是,对f(x)按位求反然后加1,而我们发现这个就是求补码的方法。

    下面来看符号位如何参与计算,设x,y>0,8位二进制数,7位值域,1位符号域,n=7,f(x)-f(y)=f(f(x)+2^n-f(y)),如果f(x)>f(y),那么这个差应该是正数,而2^n正好和负数的符号位1相抵消,使得结果是负的;如果f(x)<f(y),那么要从2^n上扣除这个差值,所以结果一定小于2^n,不会影响到符号位的1,而结果也正好是负数。

    这种运算背后蕴含的数学道理和同余有关,具体可以参考这两篇帖子《原码, 反码, 补码 详解》,《[原创] 原码,补码和反码

    另外,补码运算中,正正和负负会出现溢出情况,而正负则一定不会出现,对于溢出的情况可以用双符号位表示溢出情况,01表示两正数相加“上溢”,10表示两负数相加“下溢”,具体可以参考http://www.dz3w.com/info/digital/0081771.html

    第一篇总结日志,还请大家多指出错误。

posted on 2011-05-06 17:33  超级福满多  阅读(636)  评论(0编辑  收藏  举报