JAVA位运算和位运算的一些技巧
一、位运算
可以对整形数值的各个位进行操作
二、位运算符
2.1 位运算符共分为7种
>>(右移运算符)、<<(左移运算符)、>>>(不带符号右移,高位补0)、&(与运算符)、|(或运算符)、~(非运算符)、^(异或运算符)
2.2 >>(右移运算符)
-
公式:操作数>>右移的位数
-
举例:
- 37>>2
37对应的二进制为:0000 0000 0000 0000 0000 0000 0010 0101
右移两位:0000 0000 0000 0000 0000 0000 0000 1001
结果等于:37>>2 ==> 9 - -8>>3
因为操作数为负数,得如下思考(省略多余高位为0的二进制)
-8的原码:1000 1000
-8的反码:1111 0111
-8的补码:1111 1000
利用-8的补码右移三位:1111 1111
补码转为原码(取反,+1):1000 0001
结果等于:-8>>3 ==> -1
2.3 <<(左移运算符)
-
公式:操作数<<左移的位数
-
举例:
- 37<<2
37对应的二进制为:0000 0000 0000 0000 0000 0000 0010 0101
左移两位:0000 0000 0000 0000 0000 0000 1001 0100
结果等于:37<<2 ==> 148 - -8<<3
因为操作数为负数,得如下思考(省略多余高位为0的二进制)
-8的原码:1000 0100
-8的反码:1111 0111
-8的补码:1111 1000
利用-8的补码左移三位:1100 0000
补码转为原码(取反,+1):1100 0000
结果等于:-8<<3 ==> -64
2.4 >>>(不带符号右移,高位补0)
-
公式:操作数>>>右移的位数
-
举例:
- 37>>>2
37对应的二进制为:0000 0000 0000 0000 0000 0000 0010 0101
右移两位:0000 0000 0000 0000 0000 0000 0000 1001
结果等于:37>>>2 ==> 9 - -8>>>3
因为操作数为负数,得如下思考
-8的原码:1000 0000 0000 0000 0000 0000 0000 1000
-8的反码:1111 1111 1111 1111 1111 1111 1111 0111
-8的补码:1111 1111 1111 1111 1111 1111 1111 1000
利用-8的补码右移三位:0001 1111 1111 1111 1111 1111 1111 1111
结果等于:-8>>>3 ==> 536870911
2.5 &(与运算符)
- 运算技巧:两个数字同时为1,结果为1,其余为0。
- 举例:
- 1 & 1 = 1;
- 9 & 3
9的二进制表示为:0000 1001
3的二进制表示为:0000 0011
结果与运算: 0000 0001
转为十进制为:1
2.6 |(或运算符)
- 运算技巧:两个数字有一个为1,结果为1,其余为0。
- 举例:
- 1 | 1 = 1;
- 1 | 0 =1
- 9 & 3
9的二进制表示为:0000 1001
3的二进制表示为:0000 0011
结果或运算: 0000 1011
转为十进制为:11
2.7 ~(非运算符)
- 运算技巧:取反,0变1,1变0。
- 举例:
- ~1 = 0
- ~0 = 1
- ~9
9的二进制表示为:0000 1001
结果非运算: 1111 1111 1111 1111 1111 1111 1111 0110
运算结果为负数,转原码:1000 0000 0000 0000 0000 0000 0000 1010
转为十进制为:-10
2.8 ^(异或运算符)
- 运算技巧:相同为0,相异为1.
- 举例:
- 1 ^ 1 = 0
- 1 ^ 0 = 1
- 4 ^ 3
4的二进制表示为:0000 0100
3的二进制表示为:0000 0011
结果异或运算: 0000 0111
转为十进制为:7
异或有如下特性:
1、可以理解为不进位加法:
1 + 1 = 0
1 + 0 = 1
0 + 1 = 1
0 + 0 = 0
2、具有交换律,可以任意交换因子的位置,结果不变
A ^ B ^ A == A ^ A ^ B
3、具有结合律
A ^ B ^ A = A ^ (B ^ A)
4、对于任何数,同自己求异或为0,同0求异或为自己
X ^ X = 0
X ^ 0 = X
5、自反性,连续和同一个因子异或结果为自己
A ^ B ^ B = A ^ 0 = A
6、求负整数的反码
A ^ -1
与或非异或关系表
A | B | A & B | A 或 B | ~A | A ^ B |
---|---|---|---|---|---|
0 | 0 | 0 | 0 | 1 | 0 |
0 | 1 | 0 | 1 | 1 | 1 |
1 | 0 | 0 | 1 | 0 | 1 |
1 | 1 | 1 | 1 | 0 | 0 |
三、判断一个整数是奇数还是偶数
任意一个数 X & 1 = 1时,为奇数
十进制33的二进制为: 0010 0001
0010 0001
&
0000 0001
————————
0000 0001结果:1
任意一个数 X & 1 = 0时,为偶数
十进制32的二进制为: 0010 0000
0010 0000
&
0000 0001
————————
0000 0000结果:0
四、判断一个整数某二进制位,是1还是0
第一种:对整数的从右到左依次编号,比如求n位,为0还是1。对1进行左移n-1位,然后进行运算,最后结果在进行右移n-1位
十进制36的二进制为: 0010 0100 ,求第三位为1还是0
1左移2位 0000 0100
0010 0100
&
0000 0100
————————
0000 0100
结果:4
对结果为进行右移2位
8对应的二进制:0000 0400
8>>2 = 1
即36的对应的二进制第三位为:1
五、利用位运算进行交换整形变量的值
int x = 99;
int y = 87;
x = x ^ y;
y = x ^ y; //y = x ^ y ^ y ==> y = x
x = x ^ y; //x = x ^ y ^ x ==> x = y
System.out.println("x="+x);
System.out.println("y="+y);
输出结果:
x=87
y=99
六、不用判断语句,求整数的绝对值
- 对于任意一个正整数n或者负整数n,右移31位结果必为0或==-1==。
- 用n异或上n右移31位的结果(n ^ (n >> 31) ),如果为n为正整数结果 = n,如果为n 为负整数结果为n的反码。
- n无符号右移31位,结果为如果为n为正整数结果 0,如果为n 为负整数结果为1
- 上述 2和3做和就可以算出绝对值:(n ^ (n >> 31)) + n>>>31
例如:
整数: -32
公式拆解:n >> 31
- 对应二进制位(补码):1111 1111 1111 1111 1111 11111 1110 0000
- 右移31位(补码):1111 1111 1111 1111 1111 11111 1111 1111
- 转为原码:1000 0000 0000 0000 0000 0000 0000 0001
- 结果为 n >> 31 = -1
公式拆解:n ^ (n >> 31)
-32 对应补码:1111 1111 1111 1111 1111 11111 1110 0000
^(异或)
-1对应补码: 1111 1111 1111 1111 1111 11111 1111 1111
————————————————————
0000 0000 0000 0000 0000 000 0001 1111
结果为:31
即为 -32的反码。
公式拆解:n>>>31
(反码和补码结果差1)
-32 对应补码:1111 1111 1111 1111 1111 11111 1110 0000
-32>>>31 = 0000 0000 0000 0000 0000 0000 0000 0001
n>>>31 = 1;
综上所述:
(n ^ (n >> 31)) + n>>>31 = 31+ 1 = 32.