文章目录
说明
在看JDK源码的过程中,可以看到很多关于位运算的内容,位运算当然涉及计算机中二进制数字的存储方式以及值之间的转换,本文介绍一下二进制的三种表示方式:原码、反码、补码。
概念
原码: 将最高位作为符号位(0表示正,1表示负),其它数字位代表数值本身的绝对值。
反码:正数的反码和原码相同
。如果是负数,则将原码符号位不变
,其余各位取反,得到的就是负数的反码。
补码:正数的补码和原码相同
。如果是负数,则将原码符号位不变
,其余各位取反,然后将得到的数值加1(负数的补码也可以理解成反码加1)。
示例
通过上面的介绍,我们已经知道了几种二进制码之间的关系,下面用一个示例更直观表示一下。为了计算方便起见,假设计算机存储的是8位
下的值。
十进制数 | 原码 | 反码 | 补码 |
---|---|---|---|
+127 | 0111 1111 | 0111 1111 | 0111 1111 |
+1 | 0000 0001 | 0000 0001 | 0000 0001 |
+0 | 0000 0000 | 0000 0000 | 0000 0000 |
-0 | 1000 0000 | 1111 1111 | 0000 0000 |
-1 | 1000 0001 | 1111 1110 | 1111 1111 |
-127 | 1111 1111 | 1000 0000 | 1000 0001 |
总结一下:
正数的原码、反码、补码是相同的
。- 负数的反码是
符号位不变其余按照原码按位取反
,负数的补码是反码加1
; - 计算机运算以及存储都是基于
补码
形式。 - 0的补码只有唯一表示
0000 0000
- -128没有原码和反码,因为已超表示范围,
原码和反码区分正0负0,但是补码不需要
,空出来的这个位置用来表示-128即1000 0000 - 8位有符号数值的范围为
[-128,127)
注意包含-128
计算机中二进制为什么使用补码表示
这里面牵扯到一个很重要的计算方式模
运算。通过模运算实现化减为加
,本质上是将溢出的部分舍去而不改变计算结果。
8位运算的模为256=2^8。
在无符号位的情况下:127+2=129
129超出了8位运算的最大表示范围,所以上面的二进制的结果1000 0001表示的转换为原码为1111 1111即为-127。意思就是说129在计算机中的表示和-127是一样的,就像是时钟过了12点重新从0点开始了,超过了最大的数就从最小的数开始,256类似于时钟的一圈。
这里我们可以得出结论:负数的补码为模减去该数的绝对值
以-3为例:
-3原码:1000 0011
-3反码:1111 1100
-3补码:1111 1101
使用模运算计算结果:-3=256-3=253=1111 1101(二进制)
根据下面的例子我们看一下补码是如何化减为加
的
127-3=127+(-3)=124=0111 1100(二进制)
由于我们存储的是8位,因此溢出舍弃
得到的是0111 1100=124(十进制),因此补码的化减为加核心是通过溢出舍弃
操作来完成的。