一、Java中支持的位运算
- 位与(&):二元运算符,两个为1时结果为1,否则为0
- 位或(|):二元运算符,两个其中有一个为1时结果就为1,否则为0
- 位异或(^):二元运算符,两个值不相同,则异或结果为1。两个值相同,则异或结果为0。
- 位取非(~):一元运算符,取反操作
- 左移(<<):一元运算符,按位左移一定的位置。高位溢出,低位补0,符号位不变。其值相当于乘2。
- 右移(>>):一元运算符,按位右移一定的位置。高位补符号位,符号位不变,低位溢出。其值相当于除2。
- 无符号右移(>>>):一元运算符,符号位(即最高位)保留,其它位置向右移动,高位补零,低位溢出。
二、应用举例
-
判断int型变量a是奇数还是偶数
a&1 = 0 偶数
a&1 = 1 奇数 -
取int型变量a的第k位,即
a>>k&1
-
将int型变量a的第k位清0
a=a&~(1<<k)
-
将int型变量a的第k位置1
a=a|(1<<k)
-
int型变量循环左移k次 (设sizeof(int)=16)
a=a<<k|a>>16-k
-
int型变量a循环右移k次(设sizeof(int)=16)
a=a>>k|a<<16-k
-
整数的平均值。对于两个整数x,y,如果用 (x+y)/2 求平均值,会产生溢出,因为 x+y 可能会大于INT_MAX,但是我们知道它们的平均值是肯定不会溢出的,我们用如下算法:
int average(int x, int y) //返回X,Y 的平均值 { return (x&y)+((x^y)>>1); }
-
判断一个整数是不是2的幂,对于一个数 x >= 0,判断他是不是2的幂
boolean power2(int x) { return ((x&(x-1))==0)&&(x!=0); }
-
不用 temp交换两个整数
void swap(int x , int y) { x ^= y; y ^= x; x ^= y; }
-
计算绝对值
int abs( int x ) { int y = x >> 31 ; return (x^y)-y ; //or: (x+y)^y }
-
取模运算转化成位运算 (在不产生溢出的情况下)
a % (2^n) 等价于a & (2^n - 1)
-
乘法运算转化成位运算 (在不产生溢出的情况下)
a * (2^n) 等价于 a<< n -
除法运算转化成位运算 (在不产生溢出的情况下)
a / (2^n) 等价于 a>> n
例: 12/8 == 12>>3 -
取余a % 2 ,等价于
a & 1
-
if (x == a) x= b;
else x= a;
等价于 x= a ^ b ^ x; -
x 的 相反数,表示为
(~x+1)
口诀
清零取反要用与:a & b = (1100)
某位置一可用或
取反交换用异或
位运算符的应用 (源操作数s 掩码mask)
(1) 按位与-- &
- 清零特定位 (mask中特定位置0,其它位为1,s=s&mask)
- 取某数中指定位 (mask中特定位置1,其它位为0,s=s&mask)
(2) 按位或-- |
常用来将源操作数某些位 置1,其它位不变。 (mask中特定位置1,其它位为0 s=s|mask)
(3) 位异或-- ^
1 使特定位的值取反 (mask中特定位置1,其它位为0 s=s^mask)
2 不引入第三变量,交换两个变量的值 (设 a=a1,b=b1)
目标 | 操作 | 操作后状态 |
---|---|---|
a=a1^b1 | a=a ^b | a=a1 ^b1,b=b1 |
b=a1 ^ b1 ^ b1 | b=a ^b | a=a1 ^b1,b=a1 |
a=b1 ^a1 ^ a1 | a=a ^b | a=b1,b=a1 |
二进制补码运算公式:
-x = ~x + 1 = ~(x-1)
~x = -x-1
-(~x) = x+1
~(-x) = x-1
x+y = x - ~y - 1 = (x|y)+(x&y)
x-y = x + ~y + 1 = (x|y)-(x&y)
x^y = (x|y)-(x&y)
x|y = (x&~y)+y
x&y = (x|y)-x
x==y: ~(x-y|y-x)
x!=y: x-y|y-x
x< y: (x-y)((xy)&((x-y)^x))
x<=y: (x|y)&((x^y)|(y-x))
x< y: (x&y)|((x|y)&(x-y))//无符号x,y比较
x<=y: (x|y)&((x^y)|(y-x))//无符号x,y比较