原码反码和补码都是计算机中表示数字的一种编码,维基百科上说
编码是信息从一种形式或格式转换为另一种形式的过程。
其实,计算机内部使用二进制,n位的二进制一共可以表示2^n个不同的数字,至于具体哪个二进制序列对应哪个数字,原则上可以随意。
例如,我们可以编码 00代表数字2 01代表数字3 10代表7 11代表9 ……
但是实际应用时,必须考虑到这种编码可以给应用带来方便。相信没有人会设计上图中的编码 ==因为这种编码需要制定每一个数字的编码,而且面对编码根本不知道表示的是哪个数字,只有查表……
从这个扯淡的例子中,我们看到编码必须有一定的规律性,最好能够直接从编码计算得到表示的数字。
二进制数字
计算机采用二进制,而一个数字也可以写成二进制形式,这种一一对应关系恰好可以用于编码。
我们先看一下关于进制的知识:
我们平时使用的数字是十进制,它的全称是10进位计数制,它以10为基数,有0到9 十个符号,进位规律是“逢十进一”,它在表示一个数时,不同的位上的数字的含义是不同的。例如,个位上的3表示3 而十位上的3就表示3*10 。
与十进制类似,以2为基数(有两个符号0 1)的进位计数制称为二进制。
我们以二进制数字1011001.1011为例,二进制数字上的每一位的位权如下图所示
1011001.1011的十进制形式 为 64 + 16 + 8 + 1 + 1/2 + 1/8 + 1/16 = 89.6875
原码
使用数字的二进制形式在计算机中表示数字,对于一个正数,例如6 ,(6=4+2+0)我们可以很快写出它的二进制形式110 。但是对于负数-6,二进制形式为-110,但是计算机并不认识负数(-)。一个很自然的想法是,用一位二进制0或1分别表示正数和负数(其实也可以用其他方式,只要区分就可以,但这种方式是最方便自然的)。我们把这一个标示符号的为叫做符号位,而数字6的表示部分叫做数值位。
加上符号位之后,6就可以在计算机内表示为0110 ,而 -6可以表示为1110 。(这是用4位表示的情况)
这就是原码,由符号位加上数字绝对值的二进制形式作为数值位表示。
原码对人来说阅读起来十分方便,但是对计算机来说,却有着不少缺点。
- 原码表示法中,0有两种不同的表示方法0和-0: 以8位表示1个数字为例 0000 0000 和1000 0000都表示0 。这对于计算机来说很不友好,如果判断一个数是不是0要做两次判断。
- 求两个数的和的时候,如果符号不一致,那么不能直接相加。例如3 + (-4) 用4为2进制表示 就是0011 + 1100 ,如果直接相加 等于1111 这个结果和3+(-4)的正确结果没什么关系。由此可见,符号不相同的时候必须先判断一下两个数的绝对值,绝对值较大的减去较小的,符号是跟绝对值较大的数相同。这样进行加法运算是十分复杂的。
反码
由于用原码计算的时候要单独考虑符号位,比较麻烦,于是人们开始探索将符号位一起进行运算的方法。
反码的定义:正数的反码就是他的原码,负数的反码是他的原码的数值位取反~符号位仍为1.
使用反码表示后,符号位可以一起参与运算,不过有着一些缺点
- 加法产生进位的时候,要在最低位加上1
- 0仍有两种表示方式 0000 0000 和 1111 1111
由于这些缺点,反码的应用大大不如补码。
补码
使用原码的时候,正数加负数,实际却要进行减法,而负数减负数,实际却要进行加法,这是十分复杂的。引入补码的目的是方便的实现运算器对于有符号数的加减法运算。
模
补码是建立在“模”的概念的基础上的。模可以理解为一个量程,一个范围,当运算超出模的范围的时候会循环到最开始。
以钟表为例,要把时针从2点移动到4点,既可以顺时针转2小时,也可以逆时针转10小时。
为什么逆时针转10小时也能达到这种效果呢,这就是这种循环特性造成的。
由此我们可以说,对于模12来说
4 = 2 + 2 (mod 12)
4 = 2 +(-10) (mod 12)
也就是说模12的情况下对2进行+2 和 -10 效果是一样的。我们说2和-10对模12互补。
同理,在这个钟表上,-1和+11是一样的,-5和+7的结果是一样的。
所以计算的时候 -6 可以看做+6 -3可以看做+9
再想一下,在这个表上,一个数如果减去一个小余模12的数,相当于加上(12-这个数)
因此,可以把减法转换为加法。
补码和数字之间的映射关系
以3位为例
3位的二进制可以表示8个数字,其中分为两部分,负数和非负数。0和正数的补码就是它们的原码,而负数的补码就要是它们的绝对值相对于2^4的补码。
-1的绝对值 1 它的补码 就是相对于1 000 来说的补码 1000 – 1 = 111
-2的绝对值 10 它的补码 1000 – 10 = 110
-3的绝对值 11 补码 1000 – 11 = 101
-4的绝对值 100 补码 1000-100=100
用多少个位表示补码,它的模就是1后面有多少个0 。例如用8位表示,它的模就是1 0000 0000 = 2^8
用这个表示的时候 如果计算3-2 ,可以计算3 + (-2)
用他们的补码计算 011 + 110 = 1001 由于只有3位 第4位舍去,结果正好是001 也就是1
补码的计算
补码只是一种相对合理的编码方案,对于人来说可以用补码的形式求出,但是对于计算机来说却不好操作。所以人们又研究出了许多种求补码的方法。
- 利用定义,也就是负数的补码 = 2^n+1 + x
- 利用补码=反码+1
- 扫描方法
将负数的原码或真值转换为补码,可以从最低位开始,到最高位依次扫描,如果没有遇到1 就保持不变(开始的0仍是0) 遇到第一个1后,1后面的各个位数依次取反。最后将最高位符号位置为1.这种方法对人和机器都非常方便。
移码
移码就是将x加上一个常数,相当于在数轴上向右平移了一段距离。
常用的移码距离是2^n 。
移码可以这样理解,本来-128 到 127 256个数字都是用-128和127表示,但是经过移码后,-128到127依次映射为0-255
对于补码,它的移码就是最高位翻转,这样0表示负数 1表示正数,利于判断大小,被用在浮点表示中。