深入浅出之原码、反码、补码

我平时看JDK源码,遇到过很多位移运算,因为对位运算理解不深,严重影响了对JDK源码的理解,因此特意恶补了一下计算机组成原理的相关知识,这篇从计算机的原码、反码、补码开始讲起……

进制转换

正整数十进制转换二进制:除二取余,然后倒序排列,高位补零
正整数二进制转换十进制:整数二进制用数值乘以2的幂次依次相加

原码

由计算机的硬件决定,任何存储于计算机中的数据,其本质都是以二进制码存储,因此无论是原码、反码还是补码本质上都是二进制数。

根据冯~诺依曼提出的经典计算机体系结构框架。一台计算机由运算器,控制器,存储器,输入和输出设备组成。其中运算器,只有加法运算器,没有减法运算器(据说一开始是有的,后来由于减法器硬件开销太大,被废了 )

虽然计算机没有减法运算器,但减法其实也是一种另类的加法,比如4-1=3,也可以计算成4+(-1)=3,因此在计算机中我们为了表示正数和负数,所以引入了符号位的概念,那么以高位的1表示负数,高位的0表示正数,其余位依次是数的绝对值转换为二进制表示,这种二进制码我们称之为原码。

计算机引入原码是为了计算,那么计算机通过原码是否能有效的算出正确结果呢,下面我们来验证一下,分别以4位二进制,分别进行正数+正数、正数+负数、负数加负数的运算,是否能够得到正确结果呢

十进制 二进制 验证结果
3 + 1 = 4 0011 + 0001 = 0100(4) 正确
3 - 1 = 2 0011 + 1001 = 1100(-4) 错误
-3 - 1 = -4 1011 + 1001 = 0100(4) 错误

从结果上来看,计算机使用原码进行计算,不能得到正确的结果,那么设想负数是正数的相反数,那么除符号位,其余各位按位取反来表示负数来计算试试呢,这里引入了反码的概念

反码

因为反码的引入是为了计算减法,那么也正说明了正数的反码是它本身,负数的反码就是符号位不变,其余各位按位取反,那么以反码进行计算,来验证一下是否可以得到正确的结果呢

十进制 二进制 验证结果
3 + 1 = 4 0011 + 0001 = 0100(4) 正确
3 - 1 = 2 0011 + 1110 = 0001(6) 错误
-3 - 1 = -4 1100 + 1110 = 1010(-5) 错误

引入了反码之后,负数加负数结果是错误的,不过仔细想想也不是什么大事,负数加负数可以当成正数加正数,然后符号位强行置为1就好了,但还没有解决正数加负数的问题,所以又引入了补码来进行计算

补码

看过计算机组成原理的都知道

正数的补码等于他的原码,负数的补码等于反码+1
负数的补码等于他的原码自低位向高位,尾数的第一个‘1’及其右边的‘0’保持不变,左边的各位按位取反,符号位不变

这是补码的两种求解方式,但没有解释出补码的由来

我们以4位无符号二进制数为例,取值范围0000~1111,也就是0到15,那么15再向上加1会发生什么呢,15加1等于16,16的二进制数是10000,但是计算机是有位数限制的,比如int类型的值占4位字节,每个字节8bit,那么也就是32位,而这里是4位,那么舍弃最高位后,剩下的值就是0000,看出来没,这又是一个循环。

也就是说4位二进制数的最大值是15,那么15-15和15+1应该是等价的,所以这里减去一个数可以转换为加上另外一个数来计算。

4位二进制数引入了符号位之后,它们的值分别为:

二进制 十进制 二进制 十进制
0000 +0 1000 -8
0001 1 1001 -1
0010 2 1010 -2
0011 3 1011 -3
0100 4 1100 -4
0101 5 1101 -5
0110 6 1110 -6
0111 7 1111 -7

因为0000已经表示+0了,所以1000这里规定表示-8,那么从图中我们可以看出来规律,负数绝对值的最大值是8,8就代表4位有符号二进制的最大容量,那么负数的补码就是最大容量值减去负数的绝对值,符号位不变,通过补码的计算方法验证一下:1010(-2)的补码1110(-6),验证成功。

那么使用补码进行计算呢

十进制 二进制 验证结果
3 + 1 = 4 0011 + 0001 = 0100(4) 正确
3 - 1 = 2 0011 + 1111 = 0010(2) 正确
-3 - 1 = -4 1101 + 1111 = 1100(-4) 正确

通过补码来进行有符号位的计算,在各种情况下都是准确的,所以计算机对数字都是通过补码进行计算和存储的。

小结

这篇文章主要讲的是原码、反码和补码的由来,以及它们的计算方式,因为有些结论是基于自己的理解和验证得出的,不具有权威性,如果有错误,欢迎指正。

你可能感兴趣的:(计算机组成原理,补码)