我们知道位运算是将数字转换成二进制一位一位的进行操作,包括左移(<<)右移(>>)无符号右移(>>>),与(&)或(|)取反(~)异或(^)等等。
下面介绍一下它们:
左移(<<):
举个例子:1<<3,将1左移三位,1的二进制表示为0000 0000 0000 0000 0000 0000 0000 0001,左移三位,变成0000 0000 0000 0000 0000 0000 0000 1_ _ _最后三位空出了,规定补零,最终结果:0000 0000 0000 0000 0000 0000 0000 1000,转换成十进制就是8,也就是扩大了2^3,扩大了8倍。
对于负数的左移和这个原理一样,比如将-1<<3,将-1左移三位,计算机中负数是采用的补码的方式储存的,-1的补码是1111 1111 1111 1111 1111 1111 1111 1111左移三位补零1111 1111 1111 1111 1111 1111 1111 1000,这就是-8的补码,所以-1<<3得到的值为-8
所以左移几位相当于扩大了2的几次幂,正负数通用。
右移(>>):
右移就是将数的二进制形式右移,比如-1>>3,_ _ _1 1111 1111 1111 1111 1111 1111 1111,最高位空出来了三位,用符号位补满,因为-1的符号位为1(代表负数),所以最高三位补1,得到1111 1111 1111 1111 1111 1111 1111 1111还是-1的补码,值还是-1,所以-1不管右移几位还是-1。
无符号右移(>>>):
无符号右移就是右移后对高位空出来的不管是正是负,一律用0补满。在java和javascript中都有,但是c++中并没有这个运算符,可以把树转换成无符号的数然后进行右移操作
代码如下
int num = -4;
int res = unsigned)num >> 3;
对于有>>>运算符的
int num = -4;
int res = num >>> 3;
两者的结果是一样的
与(&):
与运算是按位相与,其中只有同时为1才为1,否则为0,比如3 & -1 转换成二进制
0000 0000 0000 0000 0000 0000 0000 0011 &
1111 1111 1111 1111 1111 1111 1111 1111每位相与
0000 0000 0000 0000 0000 0000 0000 0011所以结果为 3
或(|):
与运算是按位相与,其中只有同时为0才为0,否则为1
取反(~):
取反就是将所有位取反,0变成1,1变成0,是一元运算符,注意的是取反并不是取得相反数,而是比相反数小一的数,比如~-3 = 2,~2 = -3
异或(^):
异或操作:每位如果相同就取0, 否则就取1
位运算的操作都不会改变原数值,而是返回一个结果
比如:
int a = 1;
int res = a >> 1;
a == 1//true
res == 0// true
res = a & 0x0000;
a == 1;//true
res == 0//true
如果原来的数值也改变,可以用 a >>= 1(等价于 a = a >> 1)此类的方法写。