二进制原码、反码、补码

二进制原码、反码、补码

以前在大学看到二进制原码、反码、补码这些的时候几乎是一眼略过,因为觉得和上层开发没什么关系,现在因为有个项目要做音频流的封装,就需要对二进制进行操作了,这里复习一下。

任何数据在计算机中都是以二进制进行存储的,对于一个数,计算机要使用一定的编码方式进行存储,原码、反码、补码是机器存储一个具体数字的编码方式。

原码

原码是人脑最容易理解和计算的表示方式

就是符号位加上值的绝对值,其中第一位表示符号位,其余位表示值。逼入8位二进制:

+1=0000 0001

-1=1000 0001

因为第一位是符号位被占用了,所以8位的二进制取值范围是:

[1111 1111 , 0111 1111]

[-127 , 127]

反码

补码表示方式人脑无法直观看出其数值的. 通常也需要转换成原码在计算其数值.

正数的反码是其本身

负数的反码是其原码的基础上,符号位不变,其余各个位取反。

+1= 0000 0001原 = 0000 0001反

-1= 1000 0001原 = 1111 1110反

补码

补码表示方式人脑无法直观看出其数值的. 通常也需要转换成原码在计算其数值.

正数的补码就是其本身

负数的补码是其反码的基础上,最后+1。

+1= 0000 0001原 = 0000 0001反 = 0000 0001补

-1= 1000 0001原 = 1111 1110反 = 1111 1111补

存在的意义

既然原码最利于人脑直接阅读,那为什么还有反码和补码的存在呢,因为当涉及到计算时,当涉及原码符号位加减会让加减变得异常复杂。

例如:1-1=1+(-1)=0000 0001 + 1000 0001 =1000 0010 = -2 这明显是错误的

  • 反码计算

    由于使用原码进行计算时当遇到减法会导致运算结果出错,人们开始研究如何将符号位参与运算。也就是反码。

    1-1=1+(-1)=0000 0001 + 1111 1110 = 1111 1111反 = 1000 0000原 =-0=0

    这样其实就已经解决了原码无法进行减法的问题,但是有一个缺点,就是0的时候,在人类的理解里,+0和-0是一样的,但是在补码里面是可能出现0000 0000 和1000 0000两种编码表示0的情况,于是补码出现了。

  • 补码计算

    1-1=1+(-1)=0000 0001 + 1111 1111 = 0000 0000补 = 0000 0000原 =0

    使用补码, 不仅仅修复了0的符号以及存在两个编码的问题, 而且还能够多表示一个最低数. 这就是为什么8位二进制, 使用原码或反码表示的范围为[-127, +127], 而使用补码表示的范围为[-128, 127].

    因为机器使用补码, 所以对于编程中常用到的32位int类型, 可以表示范围是: [-231, 231-1] 因为第一位表示的是符号位.而使用补码表示时又可以多保存一个最小值.

注意

在java中二进制都是以补码进行编码的,因此我们经常可以看到有这样一种说法:

Java中Byte类型的取值范围是-128~127

很多人包括我当年在学习这块的时候也是一脸懵逼,为什么不是对称的呢,一般讲解的时候也不会讲的太仔细很容易就忘记了,这里知道了补码编码原理就容易理解多了。

8位原码和反码的取值范围是-127~127,比补码少了一个数,这是为什么呢,因为刚才上面说到了原码和补码中是有+0和-0之分的,因此取值范围刚好是对称的,而在补码中,仅存在0这个数字。因此就可以出一位来表示其他数字。

那么问题来了,为什么空出来的刚好是-128呢,可以通过以下进行推导。

原1111 1101=反1000 0010=补1000 0011=-125

原1111 1110=反1000 0001=补1000 0010=-126

原1111 1111=反1000 0000=补1000 0001=-127

只看补码有没有发现什么规律

那么我们补码空出来的值为:1000 0000应该是多少呢

根据上面的规则可以看出 补1000 0000=-128

总结

总算是解决了一直一来在心里困扰着我的问题,现在再去理解很多关于byte二进制相关的计算就清楚明了多了。

猜你喜欢

转载自blog.csdn.net/ccw0054/article/details/78802868