Java基础——原码、反码、补码 以及 位运算

有些工作几年的同学已经忘记了大学学过的计算机基础(没错,说的就是我),于是把一些基础的东西拎出来复习一下。

原码、反码、补码

首先要知道,计算机使用的是补码。为什么要用补码呢?慢慢往下看。

  • 原码

原码就是符号位加上真值的绝对值, 即用第一位表示符号, 其余位表示值. 比如如果是8位二进制:

[+1]原 = 0000 0001
[ -1]原 = 1000 0001

第一位是符号位,所以8位二进制数的取值范围是[1111 1111,0111 1111],即[-127,127]。

  • 反码

正数的反码和原码相同,负数的反码为:符号位不变,数据位取反。

[+1]反= 0000 0001
[-1]反= 1111 1110

  • 补码

正数的补码等于原码。负数的补码等于反码+1。

[+1] = [0000 0001]原 = [0000 0001]反 = [0000 0001]补
[-1] = [1000 0001]原 = [1111 1110]反 = [1111 1111]补

计算机为什么使用补码?

对于人来说,可以理解符号位的概念,计算加减时会计算真值位。但是计算机并不理解符号位,需要设计一种符号位也可以参与加减的方法。同时减法可以转换成加法,于是对于计算机来说更简单了。

假设符号位参与运算,首先来看原码:
计算十进制的 1-1=0;

1 - 1 = 1 + (-1) = [00000001]原 + [10000001]原 = [10000010]原 = -2

很明显是错的。
现在用反码来运算:

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

从结果来看。真值部分是正确的,问题出在符号位。虽然我们知道-00都是0,但是这个-是没有意义的,怎么能干掉它呢?

来看补码的运算结果:

1-1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原 = [0000 0001]补 + [1111 1111]补 = [0000 0000]补=[0000 0000]原

很完美,结果是正确的,也没有符号位问题。
所以,计算机就用补码来表示数据啦。
使用补码, 不仅仅修复了0的符号以及存在两个编码的问题, 而且还能够多表示一个最低数. 这就是为什么8位二进制, 使用原码或反码表示的范围为[-127, +127], 而使用补码表示的范围为[-128, 127]。

计算机用补码,把符号位参与运算,这其中有什么数学原理呢?有兴趣的同学可以了解一下同余定理。

位运算

Java里保留了二进制的位运算操作,日常开发中位运算不是很常用,但是巧妙的使用位运算可以大量减少运行开销,优化算法。

&:按位与。都为1时为1,否则为0
|:按位或。有一个为1时就为1,否则为0
~:非。取反
^:按位异或。相同为0,不同为1
<<:左位移运算符。左边溢出的被丢弃,右边补0
>>:带符号右位移运算符。正数时左边补0,负数时补1
<<<:无符号右移运算符。不考虑符号位,高位补0,低位溢出时丢弃

计算机怎么计算加法?

当然是用位运算实现的。

计算机计算二进制加法是分三部,第一步为将两个加数转换为二进制数,计算两个加数不需要进位的和(利用异或运算 ^ ),得出的结果。第二部将两个加数进行与运算(&)。第三部利用与运算得到结果进行左移运算(<<)(同时为计算两个加数需要进位的和),得出结果。将或异运算的结果和左移运算的结果作为两个新的加数,重复此操作。直到当与运算的结果为0,则异或运算的结果则为两个加数的和所对应的二进制数。

image.png

你可能感兴趣的:(Java基础——原码、反码、补码 以及 位运算)