java中常用的7个位运算符:
& 同为1则为1 否则为0
| 一位为1 则返回1
~ 将操作数的每位取反
^ 两位相同时返回0,不同时返回1
<< 左移运算符 将操作数的二进制码整体左移指定位数,右边空出的以0填充 正数---乘2^n
>> 右移运算符 将操作数的二进制码整体右移指定位数,左边空出的以符号位填充(如果是正数,就是以0填充。如果是负数,就是以1填充。) 正数---除2^n
>>>无符号右移运算符 将操作数的二进制码整体右移指定位数,左边空出来的位总是以0填充。 正数---除2^n
说明:位运算的效率高于乘除运算,因为计算机底层就是0 1二进制来处理的。
位运算优先级
~的优先级最高,其次是<<、>>和>>>,再次是&,然后是^,优先级最低的是|。
位运算总的来说比较简单,但是应用却是很多,要能熟练掌握并使用常用的应用。
位运算基础操作
//对于任意整数 a 和 b,以下表达式的结果均成立
a|0 == a;
a&-1 == a;
a&0 == 0;
a^a == 0;
a^0 == a;
a|~a == -1;
a&~a == 0;
a&a == a;
a|a == a;
a|(a&b) == a;
a&(a|b) == a;
应用一:判断奇偶数
a&1 == 0;则a为偶数
a&1 == 1;则a为奇数
说明: 1的二进制表示形式除了最后一位其余所有的位都是0,所以a&1对应的除了最后一位全部是0,我们知道,一个数如果是偶数,则最后一位二进制位肯定是0,因为其他位都是2的整数次方,而如果一个数是奇数,则最后一位二进制位肯定是1。所以,当a&1 == 0时,说明a是偶数,当a&1 == 1时,说明a是奇数。
应用二:交换两数
int a = 5;
int b = 9;
a ^= b;
b ^= a;
a ^= b;
说明:直接看第二步,其实就是这样:b = b^ (a^b) = a;
因为异或运算满足交换律,一个数亦或自己结果为0,而任意一个数亦或0都等于自身,所以b = b^ (a^ b) = b^ b^ a = 0^a = a。
再来看第三步,a = a^ b;此时,a = (a^ b)^a;(第一个a为原来的a,值为5;第二个a代表的是第二步运算,其实是交换后的b的值,这里的b也是指的是为交换之前的b),所以,a = b;(b为交换之前的b),所以两数就会发生交换。
应用三:求整数的绝对值
int i = a>>31;
System.out.println(i == 0? a : (~a + 1));
说明:对于一个整数a,a>>31,若a为正数,a>>31的值为0,若a为负数,a>>31的值为-1。当 i 的值为0时,也就是当a为正数的时候,直接就输出a本身;当 i 的值为-1时,说明a为负数,输出负数的反码 + 1,也就是这个数的绝对值。
应用四:变换符号
int a = 45;
int b = -9;
System.out.println(~a + 1);
System.out.println(~b + 1);
输出结果为-45 9,即变换了正负号。
应用五:求两个数的平均值
两个数相加有时候可能相加之后的值超出了对应类型的范围,当然可以采用大数进行处理,但是还有一种方法可以处理,
(x&y)+((x^y)>>1);
如下
package com.demo;
public class WeiYunSuan {
public static void main(String[] args){
System.out.println(Integer.valueOf("11111111111111110010110",2));
System.out.println(Integer.valueOf("11111111111111010001111",2));
System.out.println((8388502 + 8388239)/2);
int a = 8388502; //a对应的十进制
int b = 8388239; //b对应的十进制
System.out.println((a&b) + (a^b)>>1);
System.out.println(Integer.valueOf("11111111111111100010010",2));
}
// a 11111111111111110010110
// b 11111111111111010001111
// a&b 11111111111111 01000 0110
// a^b 00000000000000 100011001
// a^b>>1 1000 1100
// a&b + a^b>>1 11111111111111
// 010000110
// 10001100
// 11111111111111100010010
}
执行结果:
8388502
8388239
8388370
4194255
8388370
说明了可以采用这种方法进行两个数平均值的求解
应用六:取余运算
对于 a%b,当b为2的n次方的时候 a%b等价于a&(b-1)
应用七:取int型变量的第k位
a>>(k-1)&1;运算顺序为先右移k-1位,在与1
应用八:从x位到y位共有多少个1
package com.demo;
public class WeiYunSuan {
public static void main(String[] args){
int a = 23;
int sum = 0;
System.out.println(new Integer(a).toBinaryString(a));
for(int i = 1; i <= 4; i++)
sum += a>>(i-1)&1;
System.out.println(sum);
}
}
结果:
10111
3
应用九:取末k位
a&((1<<k) - 1),当结果长度不够时,应该在最左端加上相应的0就可以了
总结
功能 示例 位运算
去掉最后一位 (101101->10110) x >> 1
在最后加一个0 (101101->1011010) x < < 1
在最后加一个1 (101101->1011011) x < < 1+1
把最后一位变成1 (101100->101101) x | 1
把最后一位变成0 (101101->101100) x | 1-1
最后一位取反 (101101->101100) x ^ 1
把右数第k位变成1 (101001->101101,k=3) x | (1 < < (k-1))
把右数第k位变成0 (101101->101001,k=3) x & ~ (1 < < (k-1))
右数第k位取反 (101001->101101,k=3) x ^ (1 < < (k-1))
取末三位 (1101101->101) x & 7
取末k位 (1101101->1101,k=5) x & ((1 < < k)-1)
取右数第k位 (1101101->1,k=4) x >> (k-1) & 1
把末k位变成1 (101001->101111,k=4) x | (1 < < k-1)
末k位取反 (101001->100110,k=4) x ^ (1 < < k-1)
把右边连续的1变成0 (100101111->100100000) x & (x+1)
把右起第一个0变成1 (100101111->100111111) x | (x+1)
把右边连续的0变成1 (11011000->11011111) x | (x-1)
取右边连续的1 (100101111->1111) (x ^ (x+1)) >> 1
去掉右起第一个1的左边 (100101000->1000) x & (x ^ (x-1))
判断奇数 (x&1)==1
判断偶数 (x&1)==0(类似x%2)
清零最低位的1 x&(x-1)
得到最低位的1 x&-x
网友评论