原码、反码、补码、“温故而知新”
以前好像数字电路里当基础知识学过,一直到后来学单片机都用到,现在在自学DSP的过程中,又遇到这个最基础的问题。一扯到2进制我就发晕,总是觉得不那么习惯。现在作了个总结,希望以后再不会在这个问题上感到困惑。
1综述:
数在计算机中是以二进制形式表示的。有两种办法表示实数:
一种是定点,就是小数点位置是固定的。一般都默认小数点在最后一位数的右方,表示整数。
一种是浮点,就是小数点位置不固定。浮点数采用 底数+尾数 的格式,其实就是所说的科学记数法。小数点在底数的最左面,尾数表示实际应将小数点向左(尾数为+)或向右(-)移动的位数。
数又分为有符号数和无符号数。
原码、反码、补码都是有符号定点数的表示方法。
有符号数的最高位为符号位,0是正,1是负。
2 原码、反码、补码
原码就是这个数本身的二进制形式。如:00000001 就是+1 10000001 就是-1。
反码表示法规定:正数的反码与其原码相同;负数的反码是对其原码逐位取反,但符号位除外。
补码表示法规定:正数的补码与其原码相同;负数的补码是在其反码的末位加1。
例子:
+1011
原码:01011
反码:01011 //正数时,反码=原码
补码:01011 //正数时,补码=原码
-1011
原码:11011
反码:10100 //负数时,反码为原码取反
补码:10101 //负数时,补码为原码取反+1
+0.1101
原码:0.1101
反码:0.1101 //正数时,反码=原码
补码:0.1101 //正数时,补码=原码
-0.1101
原码:1.1101
反码:1.0010 //负数时,反码为原码取反
补码:1.0011 //负数时,补码为原码取反+1
3关于0的问题:
数0的原码有两种形式: [+0]原=00000000B [-0]原=10000000B
数0的反码有两种形式: [+0]反=00000000B [-0]反=11111111B
数0的补码是唯一的 : [+0]补=[-0]补=00000000B
假设机器能处理的位数为8.即字长为1byte,
原码和反码能表示数值的范围为:
(-127~-0 +0~127)共256个,其中都有两个0
在补码中用(-128)代替了(-0),所以补码的表示范围为:
(-128~0~127)共256个,负数128个,0和正数128个。
注:其中(-128)没有相对应的原码和反码, (-128) = (10000000)

图中可以直观的看出补码的规律
4下面是原码、反码进行运算时遇到的问题(0的问题):
有了数值的表示方法就可以对数进行算术运算.但是很快就发现用带符号位的原码进行乘除运算时结果正确,而在加减运算的时候就出现了问题,
如下: 假设字长为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)上,在人们的计算概念中零是没有正负之分的。所以有两个表示的0不适合计算机的运算。
在补码中用(-128)代替了(-0),统一正0和负0
补码的加减运算如下:
( 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 ) 正确
5补码记数法中的运算规则
补码中符号位要与有效值部分一起进行运算。
两个用补码表示的数相加时,如果最高位(符号位)有进位,则进位被舍弃。
例如:加0111和1011结果是0010(0111+1011=10010,舍去最左边的1,结果为0010,长度保持4位)
采用2的补码记数法的机器需要知道的只是如何去加和求反就够了。
[X+Y]补= [X]补+ [Y]补
[X-Y]补= [X]补+ [-Y]补
若已知[Y]补,求[-Y]补的方法是:将[Y]补的各位(包括符号位)逐位取反再在最低位加1即可。例如:[Y]补= 101101 [-Y]补= 010011
例如,减法问题7-5与加法问题7+(-5)是相同的。
因此,如果机器被请求从7(存储为0111)中减5(存储为0101),它首先将5改变为-5(表示为1011),
然后执行0111+1011的加法过程取得0010,它表示2。
7补码与原码的相互转换过程是相同的。
已知一个数的补码,求原码的方法是:
(1)如果补码的符号位为“0”,表示是一个正数,所以补码就是该数的原码。
(2)如果补码的符号位为“1”,表示是一个负数,求原码的操作是:符号位为1,其余各位取反,然后再末位加1。
例如,已知一个补码为11111001,则原码是10000111(-7):因为符号位为“1”,表示是一个负数,所以该位不变,仍为“1”;其余7位
1111001取反后为0000110;再加1,所以是10000111。
所以,求补码的运算可以使原码和补码互相转换。一个原码的补码的补码还是他本身。
8总结
所以补码的意义就在于:
(1)补码统一正0和负0
(2)补码中符号位要与有效值部分一起进行运算。
(3)使减法运算转换为加法运算。 [a-b]补=[a]补+[-b]补
附录:
补码的身世——“模”的概念:
“模”是指一个计量系统的计数范围。如时钟等。计算机也可以看成一个计量机器,它也有一个计量范围,即都存在一个“模”。例如:
时钟的计量范围是0~11,模=12。
表示n位的计算机计量范围是0~2(n)-1,模=2(n)。【注:n表示指数】
“模”实质上是计量器产生“溢出”的量,它的值在计量器上表示不出来,计量器上只能表示出模的余数。任何有模的计量器,均可化减法为
加法运算。
例如: 假设当前时针指向10点,而准确时间是6点,调整时间可有以下两种拨法:
一种是倒拨4小时,即:10-4=6
另一种是顺拨8小时:10+8=12+6=6
在以12模的系统中,加8和减4效果是一样的,因此凡是减4运算,都可以用加8来代替。
对“模”而言,8和4互为补数。实际上以12模的系统中,11和1,10和2,9和3,7和5,6和6都有这个特性。共同的特点是两者相加等于模。
对于计算机,其概念和方法完全一样。n位计算机,设n=8, 所能表示的最大数是11111111,若再加1称为100000000(9位),但因只有8位,
最高位1自然丢失。又回了00000000,所以8位二进制系统的模为2(8)。 在这样的系统中减法问题也可以化成加法问题,只需把减数用相应的
补数表示就可以了。
把补数用到计算机对数的处理上,就是补码。