关于位运算的所有基础知识和 实际应用总结

<<   左移
>>   右移
>>>  无符号右移
&    位与
|    位或
~    位非
^    位异或


其中位非(~)是一元运算符,其他六个都是二元运算符。

这些位运算符都是作用在二进制的数上的,先列一个表描述一下这几种位运算符:

下面来一一介绍一下这几种位运算符

位运算符介绍
1、<< 左移
两个左尖括号表示左移运算符,运算符规则是:各二进位全部左移若干位,高位丢弃,低位补0。

例如:6 << 2 = 24

0000 0000 0000 0000 0000 0000 0000 0110     -> 6
0000 0000 0000 0000 0000 0000 0001 1100     -> 6 << 2 = 24


我们将6的二进位向左移动两位,低位补上两个0,高位丢弃,得出来的结果就是24。
左移常被用来做 * (2 ^ n)的运算,因为直接基于二进制运算,所以左移效率比 * (2 ^ n)高。

2、>> 右移
两个右尖括号表示右移运算符,运算符规则是:各二进位全部右移若干位,正数高位补0,负数高位补1,低位丢弃。

例如: 12 >> 2 = 3

0000 0000 0000 0000 0000 0000 0000 1100     -> 12
0000 0000 0000 0000 0000 0000 0000 0011     -> 12 >> 2 = 3


因为12是正数,右移过程中高位补上两个0,低位丢弃,得出来的结果就是3。
例如:-12 >> 2 = -3

1111 1111 1111 1111 1111 1111 1111 0100    -> -12
1111 1111 1111 1111 1111 1111 1111 1101    -> -12 >> 2 = -3


因为-12是负数,右移过程中高位补上两个1,低位丢弃,得出来的结果就是-3。
右移常被用来做 / (2 ^ n)的运算,因为直接基于二进制运算,所以右移效率比 / (2 ^ n)高。

3、>>> 无符号右移
三个右尖括号表示无符号右移运算符,运算符规则是:各二进位全部右移若干位,高位补0,低位丢弃。

例如: 12 >>> 2 = 3

0000 0000 0000 0000 0000 0000 0000 1100     -> 12
0000 0000 0000 0000 0000 0000 0000 0011     -> 12 >>> 2 = 3


我们将12的二进位向右移动两位,高位补上两个0,低位丢弃,得出来的结果就是24。

例如:-12 >>> 2 = 1073741821

1111 1111 1111 1111 1111 1111 1111 0100    -> -12
0011 1111 1111 1111 1111 1111 1111 1101    -> -12 >> 2 = 1073741821


我们将-12的二进位向右移动两位,高位补上两个0,低位丢弃,得出来的结果就是1073741821。
4、& 位与
运算规则是:当运算符两边相同位置都是1时,结果返回1,其他情况都返回0。

例如:3 & 5 = 1

0000 0000 0000 0000 0000 0000 0000 0011     -> 3
0000 0000 0000 0000 0000 0000 0000 0101     -> 5
0000 0000 0000 0000 0000 0000 0000 0001     -> 3 & 5 = 1


其中3和5的只有第一位共同为1,所以3 & 5 = 1。
5、| 位或
运算规则是:当运算符两边相同位置都是0时,结果返回0,其他情况都返回1。

例如:3 | 5 = 1

0000 0000 0000 0000 0000 0000 0000 0011     -> 3
0000 0000 0000 0000 0000 0000 0000 0101     -> 5
0000 0000 0000 0000 0000 0000 0000 0111     -> 3 \| 5 = 7


其中3和5的第一到第三位都有不为0的,所以 3 | 5 = 7。
6、~ 位非
运算规则是:将运算符后二进制数反转,0变1,1变 。

例如:~ 3 = -4

0000 0000 0000 0000 0000 0000 0000 0011     -> 3
1111 1111 1111 1111 1111 1111 1111 1100     -> ~ 3 = -4


将3的所有二进制位全部反转,所以~ 3 = -4。
7、^ 位异或
运算规则是:当运算符两边相同位置都是相同,结果返回0,不相同时返回1。

例如:3 ^ 5 = 1

0000 0000 0000 0000 0000 0000 0000 0011     -> 3
0000 0000 0000 0000 0000 0000 0000 0101     -> 5
0000 0000 0000 0000 0000 0000 0000 0110     -> 3 ^ 5 = 6


其中3和5的第一和第三位不相同,所以 3 ^ 5 = 6。
位运算符使用技巧
1、判断奇偶数
我们可以利用 & 运算符的特性,来判断二进制数第一位是0还是1。

用if ((a & 1) == 0) 代替 if (a % 2 == 0)来判断a是不是偶数。

2、交换两个数
借助临时变量
通常我们交换两个数会使用一个临时变量来帮忙:

int temp = a;
a = b;
b = temp;

 

借助累加和
如果考虑到内存,不希望使用临时变量(其实就是为了炫酷),可以这样实现:

a = a + b;
b = a - b;
a = a - b;



从数学角度来分析一下(这个解释很违和,需要在一个频道才能看懂): 
- 第一步:a = a + b 
- 第二步:b = a - b = (a + b) - b = a 
- 第三步:a = a - b = (a + b) - b = (a + b) - a = b

使用 ^ 位运算符
如果想要更炫酷一点可以使用 ^ 来帮忙实现: 
先来了解一下 ^ 的几个特性: 
- a ^ a = 0 
- a ^ 0 = a 
- (a ^ b) ^ c = a ^ (b ^ c)

a ^= b;
b ^= a;
a ^= b;



从数学角度来分析一下这个解释也很违和,需要在一个频道才能看懂): 
- 第一步:a = a ^ b 
- 第二步:b = a ^ b = (a ^ b) ^ b = a ^ (b ^ b) = a ^ 0 = a 
- 第三步:a = a ^ b = (a ^ b) ^ b = (a ^ a) ^ b = b ^ 0 = b

3、取余
其实取余算法和上面的判断奇偶数原理是一样的。

比如说我们要让a对16进行取余,那么就可以让 a & 15 得出来的结果就是余数。

可以看出15的二进制表示为:

0000 0000 0000 0000 0000 0000 0000 1111

所以 a & 15 返回值就是a二进制的最低四位,也就是 a & 15 = a / 16。

使用 & 来进行取余的算法比使用 / 效率高很多,虽然只能对2^n的数值进行取余计算,但是在JDK源码中也是经常被使用到,比如说HashMap中判断key在Hash桶中的位置。

4、其他简单应用
求相反数: ~a + 1
求绝对值: a >> 31 == 0 ? a : (~a + 1)
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值