一文带你深入理解位运算
前言
相信同学们听到“位运算”这个词都很熟悉,但是在实际应用中却很少涉及,上至十几年的老程序员,下至两三年的菜鸟,可能都没有真正弄懂过,今天就带大家深入地理解学习一遍。
程序中的所有数在计算机内存中都是以二进制的形式储存的。位运算说穿了,就是直接对整数在内存中的二进制位进行操作。运位算包括位逻辑运算和移位运算,位逻辑运算能够方便地设置或屏蔽内存中某个字节的一位或几位,也可以对两个数按位相加等;移位运算可以对内存中某个二进制数左移或右移几位等。
一. 简介
Java提供了七种位运算
位运算符 | 名称 | 含义 | 举例 |
& | 按位与 |
将参与运算的两个二进制数进行&与运算,如果两个二进制位都是1,则与运算的结果为1,其他全都为0。(0与任意数N&运算都是0) |
a&b |
| | 按位或 |
将参与运算的两个二进制数进行|或运算,两个二进制位只要其中1个是1 ,那么就是1,如果2个二进制位都是0则表示0。(0与任意数N|运算都是任意数N) |
a|b |
^ | 按位异或 | 将参与运算的两个二进制数进行^异或运算,如果2个二进制位都是0或者都是1,那么就是0,如果两个二进制位不同,则为1。 | a^b |
~ | 按位非 | 一元操作符,按位取反。每个二进制位上都取相反值,1变成0,0变成1。 | ~a |
<< | 左移 | 将一个数各二进制位全部向左移动若干位,左移运算没有有符号和无符号左移动,在左移时,移除高位的同时在低位补0 | a<<2 |
>> | 右移 | 又称为有符号右移。将一个数各二进制位全部向右移动若干位,若参与运算的数字为正数,则在高位补0;若为负数,则在高位补1。 | a>>2 |
>>> | 无符号右移 | 将一个数各二进制位全部向右移动若干位,右移之后左边都是补上0。忽略符号位 | a>>>2 |
由位运算操作符衍生而来的有:
&= 按位与赋值,|= 按位或赋值,^= 按位非赋值,<<= 赋值左移,>>= 右移赋值,>>>= 无符号右移赋值
(和 += 一个概念)
二. 实操
我们以0、1、2、4、8、16、32这几个数来演示下各运算符的逻辑,首先我们计算出这几个数的二进制分别是:
0 的二进制数为: 0000 0000 0000 0000
1 的二进制数为: 0000 0000 0000 0001
2 的二进制数为: 0000 0000 0000 0010
4 的二进制数为: 0000 0000 0000 0100
8 的二进制数为: 0000 0000 0000 1000
16 的二进制数为: 0000 0000 0001 0000
32 的二进制数为: 0000 0000 0010 0000
2.1. &按位与运算
将参与运算的两个二进制数进行&与运算,如果两个二进制位都是1,则与运算的结果为1,其他全都为0。(0与任意数N&运算都是0)
判断奇偶:n & 1 == 1则为奇数,n & 1 == 0则为偶数
判断是否是2的整数次幂:n & (n-1) == 0是2 ^ n,n & (n-1) == 1不是2 ^ n
0&2 = 0
0&4 = 0
2&4 = 0
2&8 = 0
4&12= 4
2.2. |按位或运算:
将参与运算的两个二进制数进行|或运算,两个二进制位只要其中1个是1 ,那么就是1,如果2个二进制位都是0则表示0。(0与任意数N|运算都是任意数N)
0|2 = 2
0|4 = 4
2|4 = 6
2|8 = 10
2.3. ^按位异或运算
将参与运算的两个二进制数进行^异或运算,如果2个二进制位都是0或者都是1,那么就是0,如果两个二进制位不同,则为1。
0^2 = 2
0^4 = 4
2^4 = 6
2^8 = 10
2.4. ~按位非运算
一元操作符,按位取反。每个二进制位上都取相反值,1变成0,0变成1。
~0 = -1
~1 = -2
~2 = -3
~4 = -5
~8 = -9
2.5. 左移(<<)
将一个数各二进制位全部向左移动若干位,左移运算没有有符号和无符号左移动,在左移时,移除高位的同时在低位补0
左移1位相当于乘2,x << n等价于x * (2 ^ n)。
2<<1 = 4
2<<2 = 8
2<<3 = 16
2<<4 = 32
2.6. 右移(>>又称为有符号右移)
将一个数各二进制位全部向右移动若干位,若参与运算的数字为正数,则在高位补0;若为负数,则在高位补1。
右移1位相当于除2,x >> n等价于x / 2n。
32>>1 = 16
32>>2 = 8
32>>3 = 4
32>>4 = 2
2.7. 无符号右移(>>>)
将一个数各二进制位全部向右移动若干位,右移之后左边都是补上0。忽略符号位
32>>>1 = 16
32>>>2 = 8
32>>>3 = 4
32>>>4 = 2
二. 原码、反码、补码
一个数,取绝对值大小转换为二进制数,称其为原码。正常情况下,对计算机的俩个数进行加法运算,由于不知道符号,所以对其取补码后进行运算,正数的补码是其本身,负数的补码是对其正数取反加1。
原码:正数的原码是本身,负数的原码是其正数的原码,并将最高位改为1。
以5为例:
5的二进制数(即原码):0000 0000 0000 0101
原码:0000 0101
反码:1111 1010
补码:1111 1011 (负数的补码是对其正数取反加1)
即得到-5的二进制数:1111 1011
三. 实例
把一个整数拆成2的n次方的数相加 public void pow2() { int input = 19; int m = 1; for (int i =1; i< 32; i++) { if((m & input) == m) { System.out.println(m); } m = m << 1; if(m > input) { break; } } }