位运算
一、位运算简介
在计算机中,计算机以二进制方式存储数据,即 0 、1两种状态。位运算就是直接对二进制位进行操作。计算机对数据的加减乘除都是位运算,即符号位共同参与运算的运算。
如: 20 + 13 = 33
0001 0100 20
+ 0000 1101 13
-----------------
0001 0001 33
所以,相比在代码中使用* / + - ,位运算可以更快一点
二、符号介绍
符号 | 描述 | 运算规则 |
---|---|---|
& | 与 | 两个位只有同为1时,结果才为1 |
| | 或 | 两个位只要有一个为1,结果就为1 |
^ | 异或 | 两个位不同时,结果为1。两个位相同,结果为0 |
~ | 取反 | 0变1,一变0 |
>> | 右移 | 各二进制位全部右移若干位,对无符号数,高位补0,有符号数,最高位补符号数 |
<< | 左移 | 各二进制位全部左移若干位,高位丢弃,低位补0 |
三、位运算技巧
1.关于&
假设现在有一个数,我们需要取得这个数的最后三个二进制数。
再此之前,我们思考一下,1&0 = 0,1&1 =1。
我们发现,1和任何数与,结果都是这个数。
例:10 : 0000 1010
& 7: 0000 0111
-------------------------------------
0000 0***010***
我们就得到了10的二进制数的后三位。
进一步,思考10 % 8 => 2 。实际上就是取得了这个数二进制下的后三位。我们可以得出 num % 8 <=> num & 7。
以纯二进制考虑:num % 8 相当于 num %(1000)2。
2.关于^
A | B | A^B |
---|---|---|
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 0 |
通过这样一个性质,我们可以在二进制层次进行加密解密。
明文 0010 1001
秘钥 1101 1000
^ --------------------
密文 1111 0001
秘钥 1101 1000
^ --------------------
明文 0010 1001
通过一个简单的秘钥,我们就可以对文档进行加密。
如想要进行局部加密,只需在局部位置全部为1,其他位置为0即可。
四、位运算技巧的再深入
1.置位
设置某一个位为1,称为置位
例:对0101 0010 的第四位进行置位。
再此之前,我们需要对0101 0010 进行编号,从头开始,从0开始,依次编号,则第四位为:0101 0010。
如何在不影响其他位基础下,将第四位置为1呢?
只需将0000 1000 与 0101 0010相或即可。
0000 1000
0101 0010
|
------------------
0101 1010
我们可以发现,0000 1000 其实是由0000 0001 左移三位得到的。这个左移位数可以由(7 - i)得到,i为置位的下标
通过上面的图的演示,发现(7^i) <=>(7 - i) ,由此我们可以得到置位的公式 ( num) |= ( 1 << (7^i) )
2.清位
设置某一个位为0,称为清位
例:我们再对0101 0010 的第三位进行清位。
如何在不影响其他位基础下,将第三位清为0呢?
只需将1110 1111 与 0101 0010相或即可。
1110 1111
0101 0010
&
------------------
0100 0010
我们可以发现,1110 1111 其实是由0000 0001 左移四位并且取反得到的。
通过上面的图的演示,我们可以得到置位的公式 ( num) &= ~( 1 << (7^ i) )
3.取位
取得某个位的值,称为取位
例:我们再对0101 0010 的第1位进行取位。
参考前面的方法,1与某个值,结果仍然不变。
我们使0101 0010 右移6位,得到0000 0001 与0000 0001 进行相与,等到1位的值。
通过上面的图的演示,我们可以得到置位的公式 ( num >> (7^ i) ) & 7