原码
这个东西比其他两个都好理解,因为正数和负数的原码都是一样的转换方法,就是一个数转成二进制之后的数,其中,最高位是符号位,正数的符号位为0,负数为1,比如-13,在字长为8的处理器中会表示成10001101。
反码
这个东西在正数和负数中就不一样了,正数的反码就是它的原码,而负数的反码是它的原码将全部位取反之后的数(除了符号位),就比如上面的那个-13,原码是10001101,则他的反码就是11110010
补码
这个东西在正数和负数中也不一样,正数的补码就是他的原码(正数的原码,反码和补码都一样),而负数的补码等于它的反码+1,还是拿那个-13作例子,它的反码是11110010,那么他的补码就是11110011。
原码,反码,补码的来源
二进制这个东西,它的来源不好说,有些人说是莱布尼茨发明的,又有些人说起源于中国的八卦,不管怎么说,这个东西十分的伟大,在计算机中,用二进制来运算是很方便的,每一位只有1和0两种状态,对应电路里面的每一位就是有电和没电,设计起来就很方便了。但如果你搞个十进制给它的话它基本就懵掉了,电路会麻烦到一种不可想象的程度,自然就很难高速运算了。
一开始,本来是只有正数的,那么人们就可以表示出“小明给了小红5个苹果,小红的苹果数+5”,但是后来人们想到“小明的苹果数-5”,怎么办呢,于是负数因此而生。
这时候就有个问题了,这还得说到计算机的计算,上面也说了,+-*/是最常用的,那么自然要让它变得简便,那么有了负数这个东西之后,人们想到了将a-b变成a+(-b),那么就没有“减”这种操作了,是不是很方便!但是怎么加?比如1-1,就会变成1+(-1),看似没有什么问题,但你看我算一次
00000001
+ 10000001
_____________
10000010
什么?结果竟然是-2,这可怎么办,那你总不能先判断一下它的符号位再去搞吧,那这样的话电路的复杂度一下子又上去了,这不就白费功夫了吗,那怎么办呢?于是人们发明了反码,但是,反码依然不能直接计算(比如3-2,读者可以手动模拟一下),因为它还是不完整的。
先撇开上面的东西,设想一下,假如有一个cpu的字长为3,那么可以表示的数就有-3,-2,-1,0,1,2,3,对于2-1这条式子,我们发现其实它的结果等于2+3,因为2+3的结果转成二进制就是101,因为字长为3,最高位是符号位,所以101只能保留01,最左边的1要舍弃掉,所以答案其实是一样的。
那既然可以把减法转成加法,那计算起来就很方便了,那么我们找找规律,看看负数应该变成哪个整数就可以了。
刚刚那个-1转成了+3,可以发现,1+3=4,而4正好是我们能表示的数中最大的那一个+1,于是,我们设a-b等价于a+c,则
c=最大的那一个+1-b
于是,补码出现了,还记得补码的定义吗,负数的补码是它的反码+1,仔细想想,它的反码其实就是最大的那一个减去自己,也就是 最大的那一个-b这一步,然后+1,就等于c了。
并且,补码还解决了一个问题,因为在原码和反码里面,0是有+0和-0两种表达方式的,但是,有了补码之后,-0和+0的补码是一样的,于是就只有一种表达方式了。