关闭

浅谈java中的位运算

219人阅读 评论(1) 收藏 举报
分类:

众所周知,计算机中的所有数据都是以二进制形式存储的,位运算直接作用在内存中的二进制数据,所以运算速度非常快。

首先明白一点,位运算只能用于整型数据,int 类型占4个字节,1个字节占8位,其次,要清楚6种位运算符:

&:与,只有1&1=1,其余都为0;

 | :或,只有0|0=0,其余都为1;

^ :异或,两个为相同为0,相异为1;

~:取反,各位0变1,1变0;

<<:左移,各二进制位全部左移若干位,高位丢弃,低位补0;

>>:右移,各二进制位全部右移若干位,对无符号数,高位补0,低位移除,对有符号数,java是算数右移,即高位补符号位,符号位:0正数,1负数

在计算机中负数是以其正值的补码形式存储的。

原码:对整型数直接转化为二进制数,最高位为符号位

反码:正数的反码与其原码相同;负数的反码是除符号位外对其原码逐位取反。

补码:正数的补码与其原码相同;负数的补码是在其反码的末位加1。

着重分析一下左移和右移,如下:

int i=15;//15=8+4+2+1,即 00000000 00000000 00000000 00001111
int j=-15;//11111111 11111111 11111111 11110001,负数存的是补码,
System.out.println(i<<2);// 00000000 00000000 00000000 00111100=60
System.out.println(j<<2);//11111111 11111111 11111111 11000100注意这是补码,
		        //输出的时候还要转换为原码,除符号位外逐位取反+1
		       //10000000 00000000 00000000 00111100=-60
System.out.println(i>>2);//00000000 00000000 00000000 00000011=3
System.out.println(j>>2);//11111111 11111111 11111111 11111100注意这是补码,除符号位外逐位取反+1
		         //10000000 00000000 00000000 00000100=-4

常见的利用位运算进行的操作:

1)《剑指Offer》中给出过这样一道题:写一个函数求两个整数之和,要求在函数体内不能用算数运算符加、减、乘、除。

思路:对于十进制数相加我们其实做了三步:

   (1) sum=各位相加不进位;

   (2)carry=做进位,取出进位数

   (3)result=sum+carry;

对于二进制数求和同样适用,所以函数如下:

public static int AddWithoutArithmetic(int num1, int num2)
	{
		//什么时候退出递归呢?当两数相加没有发生进位的时候
		if(num2==0){
			return num1;
		}
		//各位相加不进位,0+0=0 1+1=0;0+1=1 1+0=1 和位运算符异或(^)相同
		int sum=num1^num2;
		//做进位,取出进位值
		int carry=(num1&num2)<<1;//只有1+1才会发生进位,和运算符与(&)相同,并且二进制中的进位相当于左移一位
		return AddWithoutArithmetic(sum,carry);
	}

2)判断奇偶数

public static String OddOrEven(int n){
		if((n&1)==0){//n=4,00000000 00000000 00000000 00000100&00000000 00000000 00000000 00000001=00000000 00000000 00000000 00000000
			return "even";
		}else{//n=5;101&001=001
			return "odd";
		}	
	}
3)交换两数

public static void exchange(int a,int b){
		a^=b;//a=a^b
		b^=a;//b=b^a=b^(a^b)=(b^b)^a=0^a=a
		a^=b;//a=a^b=(a^b)^(a)=(a^a)^b=0^b=b
	}
4)变换正负号(取反+1)

System.out.println(~7+1);
		//00000000 00000000 00000000 00000111=7
	    //11111111 11111111 11111111 11111000=~7
		//11111111 11111111 11111111 11111001这是补码,转换为整数时,需要除符号为外逐位取反,再加1
		//10000000 00000000 00000000 00000111=-7
5)求绝对值

 public static int abs(int a){
		int i=a>>31;//取符号位
		return i==0?a:(~a+1);//或者return (a^i)-i;因为a^0=a;a^(-1)=~a;这种方式没用任何判断表达式包括三目表达式
	 }



1
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:9282次
    • 积分:380
    • 等级:
    • 排名:千里之外
    • 原创:26篇
    • 转载:9篇
    • 译文:0篇
    • 评论:7条