原码、反码和补码

在想看Java中的Integer.MAX_VALUE和Integer.MIN_VALUE的值的时候,看到这个这方面的知识,学习了一下,做个记录。

原码

二进制的原生表示方法,为了表示正负,使用第一位来表示正负,1表示为负数,0表示为正数

特点:

1、占用了一位数,假设计算机只有8位,那么只剩下7位用来表示数字

所以8位二进制源码的取值范围为-127~127,总共255个数,有两个0,+0和-0

2、假设只有源码,计算时会有一个问题,假设用8位表示数字,正1,00000001,负1,10000001,正1+负1=0,但是这样算会得到10000010,为-2,这样就错误了。

3、注意:用第一位用来表示正负,不管是原码还是反码、补码,这个是不变的。

反码和补码:

最初为了解决减法的问题,想到了反码。

计算机中只有加法器,也曾经发明过减法器,但是减法器的硬件开销太大,所以被淘汰了。

为什么减法开销太大

我们看看加法和减法有什么区别,我们用10进制来说明,这个比较直观,换成二进制也是一样的逻辑。为了描述方便,我们例子使用大数减去小数,反过来情况可以先将减数与被减数调换位置,然后将符号变成负数。

加法假设84 + 37 = 121

加法从右边开始计算,满位进一,这样一遍下来就全部计算完毕O(n)的复杂度

减法假设121 - 84 = 37

减法同样要从右边开始计算,但是不够需要从左边借位,不够再借,这样需要不停的递归,也就是O(n^2)的复杂度(根据1+2+3+。。。+n求和得出)

将减法变为加法

有另外一种方法来计算减法,我们先用十进制的计算公式来考虑减法如何做。假设224 - 77 = 147

取224所在最高位的最大数的999 + 1,如果四位就是9999+1=10000。

224 + (1000- 77 )- 1000

224 + 923 - 1000 =1147 -1000 = 147

我们来总结上面的例子:

1、取一个大于被减数的“单位基数”,上例为1000

这个1000是怎么算出来的,将所有位上的数设置为当前进制的最大值,得到999,然后+1。

当然,只要大于224,取多少其实都无所谓,我们取10000也照样计算,但是按照一般习惯,取大于当前最高位的十进制最小基数。

2、先加上被减数的补数,再减去一个单位的基数

3、补数的计算方式为,所有位取到进制最高位,直接求补数,然后+1。上例中,对77求补,得到922,+1得到923。

 

二进制:

同样,在二进制中也可以使用这个方法。同样,我们可以取大于当前最高位的二进制最小基数来作为基数。一般情况下,我们取计算机(虚拟机)的位来作为基数。假设8位的那么这个基数就是100000000,这个其实有它自己的名称,叫做"模",表示计算机的容量参数。

我们先加上被减数的补数,然后再减去一个单位模,就得到减法的结果。这个减去“模”怎么计算呢,使用“溢出丢失”来实现,就是这个计算机系统不可能有这么大的数出现,如果超出最大“模”的数,就直接丢掉超出的这个位,取剩下的值。

我们可以想象成一个时钟,或者表盘,假设只有最多1~100的读数,50 - 30 = 50 + (100 - 30) = 120,这个20是超出范围的,也就是120多绕了一圈,我们直接忽视这多绕的一圈就可以得到正确的结果。

计算机的减法实现:

1、取相对模的补数,做加法

2、丢弃超出模的位数

 

反码与补码:

按照上面的描述,反码和补码直接就出来了,我们把减法认为是正数与负数的求和,其中负数需要做一下转变,这个转变的过程是取反码然后取补码,然后直接相加,计算的时候不考虑符号,将溢出的部分直接丢弃。计算之后,判断两个数的大小,如果被减数大,给结果设置为负数,否则设置为正数。这样就得到减法的最终结果。

假设(方便举例,取减数较大的例子)

10 - 8 = 2;

-8 = 1001000的补数 (暂时忽略第一位1,其它为求补,然后+1) = (1)1110111 + 0000001 = (1)1111110

10 - 8 =(0)0001010 + (1)1111000 = 10000010,溢出最高位,得到0000010,也就是2

正数其实本是没必要取反码,补码的,但是为了统一处理,统一描述,我们可以先将所有的加法减法中参与运算的数值全部用补码来运算,这样就省略了后面的判断。

按照这个字路,正数的反码等于原码,正数的补码也等于原码。负数的反码等于第一位不变,其它位是原码的补数。负数的补码等于第一位不变,其它位整体的值为负数的反码+1。

总结:

1、反码是一种过渡状态,是直接求补数的值。补码是+1之后的值,这个才是最后用来计算的值。

比如-8,反码是11110111,补码就直接是11111000。

2、反码、补码都有正负位。

反码正数表示为+0 ~ 127,负数表示范围为-127~ -0

对于负数,补码因为加了1,表面看起来是-127~-0,实际是-128到-1的值,这也是为什么8位2进制能表示256个范围(-128~127)的原因。

3、被减数小怎么办,8-10,应该是判断如果被减数小,先10-8,然后手动改变最高位为负数。

上面的真正计算过程中,根本不考虑最高位,最高位只用来开始判断是否减法,然后确定运算参数大小关系,是否需要翻转再修改最高位。

4、依次类推,Integer.MAX_VALUE表示的是2^31 - 1,而Integer.MIN_VALUE表示的是-2^31。

疑问:

网上的帖子都只是介绍源码、反码、补码是什么,到底现在计算机使用的是原码、反码、补码。还是说都在用,只是不同场景使用不同的码,这个答案,找遍了网上也没找到答案。

还有就是怎么知道一个数据是原码、反码还是补码的,这个问题其实和上面一样的问题,也没找到答案。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值