前言
在实际业务中遇到了位运算,在此记录实际业务中的使用方式。如果运用位运算熟练,可以减少运行开销,优化代码算法。
一、什么是位运算
程序中的所有数在计算机内存中都是以二进制的形式储存的。位运算就是直接对整数在内存中的二进制位进行操作。
二、位操作符
既然有位运算,肯定就涉及到操作符,跟加减乘除一样,认识下位操作符。
| 操作 | 符号 |
|---|---|
| 与 | & |
| 或 | | |
| 异或 | |
| 取反 | ~ |
| 左移 | << |
| 右移 | >> |
认识完操作符当然就是实践了。
三、入门实践
我们以6(0110)和12(1100)作为接下来的例子
1、与(&):两个都为1就是1,否则为0
0110
1100
----
0100 = 4
2、或(|):两个都为0就是0,否则为1
0110
1100
----
1110 = 14
3、异或(^):两个相同就为0,否则为1
0110
1100
----
1010 = 10
4、取反(~):0为1,1为0
~0110 = -7
5、左移(<<):向左移位,低位补零,高位舍弃
0110 << 1 = 1100 = 12
6、右移(>>):向右移位,无符号高位补 0,有符号高位补符号位
0110 >> 1 = 0011 = 3
四、进阶实践
在最近接手的需求梳理代码过程中,有这样实现每日登陆/签到的标记,减少数据库的数据插入。
| mask | day | 1<<day | mask | 1 << day | bit |
|---|---|---|---|---|
| 0 | 1 | 2 | 2 | 10 |
| 2 | 2 | 4 | 6 | 110 |
| 6 | 3 | 8 | 14 | 1110 |
| : | : | : | : | : |
| 536870910 | 29 | 536870912 | 1073741822 | 00111111111111111111111111111110 |
| 1073741822 | 30 | 1073741824 | 2147483646 | 01111111111111111111111111111110 |
| 2147483646 | 31 | 2147483648 | 4294967294 | 11111111111111111111111111111110 |
我们知道一个月最多不会超过31天,所以用int32为记,从右到左开始,除开第一个0,依次往后,1代表签到过,0代表未签到。上表中,mask从零开始计数,根据日期号数增加,mask等于前一天的mask | 1<<day,再去运算当日的mask | 1 << day,就可以标记当日的签到状态。用年月(eg:202112)为key,value为mask,每次只需要在数据库更新mask的值即可。
五、尾声
当然,位运算的应用方式还有很多,推荐看这里。