1 什么是位运算
程序中的所有数在计算机内存中都是以二进制的形式储存的。位运算就是直接对整数在内存中的二进制位进行操作。比如我们平时使用的java语言中的int类型有32位,那就是由32个位组成。
/**
* @ClassName 获得一个int整形的32位二进制表达
* @Author CabbageDevil
* @Version 1.0
**/
public class bitwiseOperation {
public static void print(int num){
for(int i=31;i>=0;i--){
System.out.print((num&(1<<i))==0?"0":"1");
}
System.out.println();
}
public static void main(String[] args) {
int num=5;
print(num);
}
}
通过上面的代码我们可以得出一个int10进制的二进制32位表达,例如
1的二进制是 00000000000000000000000000000001
5的二进制是 00000000000000000000000000000101
最大int整形是2147483647 的二进制是 01111111111111111111111111111111
最小int整形是-2147483648 的二进制是10000000000000000000000000000000
也就是2的-31次方到2的31次方-1
2 关于上面介绍的一些衍生的问题
问题1: 说是32位,为什么却只有31次方,而不是32次方?
回答1:
通过上面我们可以发现,在位运算里面每一位都是前一位的2倍,可以理解成“左移=X2”,所以32位是31位的2倍,也就是4,294,967,296这个数,然而,“int最小”+“0”+“int最大”=4,294,967,296 所以我们一半给了负数,一半给了非负。
问题2: 继续上面的话题可以看到,正数是比负数少1个的,为什么呢?
回答2:
因为有0的存在,0是属于非负的,所以正数需要减少一个
问题3: 位运算如何取反?
5的二进制表达是
00000000000000000000000000000101
然而-5的则是
11111111111111111111111111111011
按取反的逻辑 -5的二进制表达应该是
11111111111111111111111111111010
才是正确的但是这里却+了1,因为这样在相互取反的时候计算机底层可以走同一套逻辑不需要进行逻辑分歧,越底层分歧越少,得到的速度也就会越快,
按上面的逻辑把 -5取反则是
00000000000000000000000000000100
+1正好是
00000000000000000000000000000101 得到了5
所以这里可以有一个公式
5取反 = -5 = ~5 + 1
问题3: 最小数取反?
在32位里面每个正数都有相对应的负数,那问题来了,最大的负数取反是谁?
最小int整形是-2147483648 的二进制是10000000000000000000000000000000
取反就是
01111111111111111111111111111111 +1
得到的还是
10000000000000000000000000000000
所以最小数取反仍然是它自己
还有 0 32位就是
00000000000000000000000000000000
取反就是
11111111111111111111111111111111
再加上1就会变成33位的
100000000000000000000000000000000,把溢出的弟33位去掉,还是0 所以0按照上面的规则取反还是0 整个底层运算都走的一个计算分支。