Java位运算及简单应用

位运算

1.位运算与移位运算
细化符号描述运算规则
按位运算&两位都为1,那么结果为1
|有一位为1,那么结果为1
~~0 = 1,~1 = 0
^异或两位不相同,结果为1
移位运算<<左移各二进制位全部左移N位,高位丢弃,低位补0
>>右移各二进制位全部右移N位,若值为正,则在高位插入 0,若值为负,则在高位插入 1
>>>无符号右移各二进制位全部右移N位,无论正负,都在高位插入0
2.原码、反码和补码
  • 原码:原码表示法在数字前面增加了一位符号位,即最高位为符号位,正数位该位为0,负数位该位为1.比如十进制的5如果用8个二进制位来表示就是00000101,-5就是10000101。

  • 反码:正数的反码是其本身,负数的反码在其原码的基础上,符号位不变,其余各个位取反。5的反码就是00000101,而-5的则为11111010。

  • 补码:正数的补码是其本身,负数的补码在其原码的基础上,符号位不变,其余各位取反,最后+1。即在反码的基础上+1。5的反码就是00000101,而-5的则为11111011。

3.位运算的应用
1.不用额外的变量实现两个数字互换
  • 通过三次异或操作完成了两个变量值的替换。

    0^a = a,a^a = 0;

    a ^ b = b ^ a;

    a ^ b ^ c = a ^ (b ^ c) = (a ^ b) ^ c;

    a ^ b ^ a = b;

    假设a,b两个变量,经过如下步骤完成值交换:a=a^b ,b=b^a ,a=a^b。

    证明如下:

    因为a ^ b = b ^ a,又a=a^b ,b=b^a。 故b=b^a= b^ (a^b)=a。

    继续a=a^b, a=(a^b) ^ b^ (a^b),故a=b。完成值交换。

    public void swapTest(){
        int a = 1, b =2;
        System.out.println(a+" "+b);//1  2
        a = a^b;
        b = b^a;
        a = a^b;
        System.out.println(a+" "+b);//2  1
    }
2.不用判断语句实现求绝对值
  • return (a^(a>>31))-(a>>31); 或 return (1 - ((a >>> 31) << 1)) * a;

    若a为正数,则不变,需要用异或0保持的特点;
    若a为负数,则其补码为原码翻转每一位后+1,先求其原码,补码-1后再翻转每一位,此时需要使用异或1具有翻转的特点。

    任何正数右移31后只剩符号位0,最终结果为0,任何负数右移31后也只剩符号位1,溢出的31位截断,空出的31位补符号位1,最终结果为-1.右移31操作可以取得任何整数的符号位。

    那么综合上面步骤,可得到公式。a>>31取得a的符号,若a为正数,a>>31等于0,a^0=a,不变;若a为负数,a>>31等于-1 ,a^-1翻转每一位。

    public static void absTest(){
        int a = -123;
        System.out.println((a ^ (a >> 31)) - (a >> 31));//123
        System.out.println((1 - ((a >>> 31) << 1)) * a);//123
    }
3. 判断一个数的奇偶性
  • 通过与运算判断奇偶数,伪代码如下:

    n&1 == 1?”奇数”:”偶数” 即判断最低位是不是0

    奇数最低位肯定是1,而1的二进制最低位也是1,其他位都是0,所以所有奇数和1与运算结果肯定是1。

    public static void main(String[] args) {
        int a = 1,b = 2;
        System.out.println(evenOrOdd(a));//true
        System.out.println(evenOrOdd(b));//false
    }

    public static boolean evenOrOdd(int n){
        return (n & 1) == 1? true : false;//奇数返回true,偶数返回false
    }
4.整数的平均值
  • 对于两个整数x,y,如果用 (x+y)/2 求平均值,会产生溢出,因为 x+y 可能会大于INT_MAX,但是我们知道它们的平均值是肯定不会溢出的。return (x&y)+((x^y)>>1); 或者 return (x +y ) >> 1;
    public static void main(String[] args) {
        int x = Integer.MAX_VALUE, y = Integer.MAX_VALUE;
        System.out.println((x & y) + ((x ^ y) >> 1));//2147483647
        System.out.println((x + y) / 2);//-1 溢出
    }
5.判断数中有多少个1
	public static void main(String[] args) {
	 	int a = 7;
	 	int count=0;
	 	while(a!=0){
	  		if((a>>1)<<1!=a){ //对a进行"右移再左移",判断其结果是否等于原来的a
	 			++count;
	  		}
	  
	  		a = a>>>1;//完成1次判断,对a进行无符号右移并把运算结果赋值给a自身
	  	}
	  	System.out.println("a转换为二进制数后,有"+count+"个1");
	}
6.判断一个数是不是2的幂
  • return ((x&(x-1))==0)&&(x!=0);x中只有一个1
7.获取int最大最小值
  • 最大return ( 1 << 31 ) - 1; 或者 return ~ ( 1 << 31 ) ;

  • 最小return 1 << 31; 或者 return 1 << - 1;

8.获取long最大最小值
  • 最大 return ( ( long ) 1 << 127 ) - 1;
  • 最小 return 1 << 127;
9.乘2除2,乘2的m次方除以2的m次方
  • return n << 1;
  • return n >> 1;
  • return n <<m;
  • return n>>m;
10.取两个数的最大值
  • return b & ( (a -b ) >> 31 ) | a & (~ (a -b ) >> 31 ); 如果a>=b,(a-b)>>31为0,否则为-1
11.取两个数的最小值
  • return a & ( (a -b ) >> 31 ) | b & (~ (a -b ) >> 31 ); 如果a>=b,(a-b)>>31为0,否则为-1
12.判断符号是否相同
  • return (x ^ y ) > 0; 即判断最高位(符号位)是否相同
13.从低位到高位,取n的第m位
  • return (n >> (m - 1 ) ) & 1;
14.从低位到高位.将n的第m位置1
  • return n | ( 1 << (m - 1 ) ); 将1左移m-1位找到第m位,得到000…1…000 n在和这个数做或运算
15.从低位到高位,将n的第m位置0
  • return n & ~ ( 1 << (m - 1 ) ); 将1左移m-1位找到第m位,取反后变成111…0…1111 n再和这个数做与运算
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值