当前位置: 首页 > 科技观察

做了这么久的程序员,你知道如何使用二进制计算吗?

时间:2023-03-21 19:13:17 科技观察

1.前言你是什么时候注意到位运算的?从毕业入职公司看老板的代码出现2<<4开始?从小白到开放阅读框架源码,看MAXIMUM_CAPACITY=1<<30;开始?或者从什么时候开始?其实二进制位运算一直就在我们身边。当你开始编写HelloWord打印输出时,就有二进制流处理,但它隐藏得很深,很难找到。所以当我们开始意识到代码和二进制之间的关系时,往往来自于看到可以用二进制完成的计算,包括;二进制计算比乘法更高效,二进制更能体现你要设置的值的大小范围。比如你要设置一个指定范围size=1073741824的Int值,那么给这样的整数值是直观,还是给二进制1<<30更直观?其实这两个值是相等的。所以在这种情况下,也会有二元运算的表现。小付在学习编程的时候,第一次注意到二元运算就是关于a和b两个值的交换。如果不引入第三个值就可以完成呢?inta=2,b=3;a=a^b;b=a^b;a=a^b;同一个帽子的^运算符,替换两个数,替换后a=3,b=2那么它是怎么做到的呢?^异或运算:在两个操作数的相同位置,如果值相同(都为0或都为1)则为0,如果不同(一个为0,另一个为1),则为1。运算是根据二进制数据解析a=2二进制数为0010,b=3二进制数为0011a=a^b=0010^0011=0001b=a^b=0001^0011=0010=2a=a^b=0001^0010=0011=3异或运算的基本定理分析a=a^bb=a^b=a^b^b=a=2a=a^b=a^a^b=b=3与二进制运算的魅力相去甚远此外,还可以完成奇偶判断、有效位计算、乘法、加法等。这些内容的学习,让我们的研发人员积累了编程逻辑,拓展了思维方式。接下来付哥就带大家学习一下。2.位运算简介位运算是编程中对位数组或二进制数的一元和二元运算。在许多较旧的微处理器上,按位运算比加法和减法稍快,通常比乘法和除法快得多。在现代架构上,位运算通常以与加法相同的速度执行(仍然比乘法快),但由于资源使用减少,通常消耗更少的功率。四种基本位操作包括;和&,或|,不是~,独占或^inta=1;//0001intb=2;//0010intc=4;//0100intd=8;//1000inte=15;//1111//与运算;0001System.out.println(Integer.toBinaryString(a&e));//0001//或运算;0011System.out.println(Integer.toBinaryString(a|b));//0011//异或运算;0101System.out.println(Integer.toBinaryString(a^c));//0101//NOT操作;...11110111System.out.println(Integer.toBinaryString(~d));和操作;两个数都转换成二进制,然后从高位开始比较,如果两个数都为1,则为1,否则为0。或运算;两个数都转换成二进制,然后从高位开始比较,只要两个数中有一个为1,则为1,否则为0。NOT运算;位为0,结果为1,位为1,结果为0。异或运算;两个数转换成二进制,然后从高位开始比较,相同则为0,不同则为1。三、位运算案例1、获取位值publicintgetBit(intnumber,intbitPosition){return(number>>bitPosition)&1;}目的:获取二进制数中指定位置的值。逻辑:该方法将目标值移动到最右边,即位数组的第0个位置,如;0001的二进制形式。然后AND与1。如果目标位为1,则结果为1,否则结果为0;2.设置位值publicintsetBit(intnumber,intbitPosition){returnnumber|(1<>31)&1)==0;}目的:判断number的值是否为正数。逻辑:根据二进制正数最左边的值为0,右移31位,与1进行与运算,结果等于1则为负数,为无论如何都是正数。7、左移两位publicintmultiplyByTwo(intnumber){returnnumber<<1;}目的:乘以2逻辑:该方法将原数左移一位。所以所有位都将乘以2,因此数字本身将乘以2。8.右移两个publicintdivideByTwo(intnumber){returnnumber>>1;}目的:除以2逻辑:此方法除以将原来的数字向右移动一位。所以所有的位都将除以2,因此数字本身将除以2,没有余数。9、正负互换publicintswitchSign(intnumber){return~number+1;}目的:正数转负数,负数转正数逻辑:通过二进制取反运算,如1000=8转1。....0111=-9+1=-810。乘法(有符号)publicintmultiply(inta,intb){intmultiply=0;while(a!=0&&b!=0){System.out.print("计算步骤("+(isEven(b)?"Even":"Odd")+"):a("+String.format("%04d",Integer.valueOf(Integer.toBinaryString(a)))+")="+a+"|b("+String.format("%04d",Integer.valueOf(Integer.toBinaryString(b)))+")="+b);//b是偶数:2a*(b/2)if(isEven(b)){a=multiplyByTwo(a);b=divideByTwo(b);}//b是奇数else{//b是正数:2a*(b-1)/2+aif(isPositive(b)){multiply+=a;a=multiplyByTwo(a);b=divideByTwo(b-1);}//b为负数:2a*(b+1)/2-aelse{multiply-=a;a=multiplyByTwo(a);b=divideByTwo(b+1);}}System.out.println("|multiply("+String.format("%04d",Integer.valueOf(Integer.toBinaryString(multiply)))+")="+multiply);}returnmultiply;}目的:计算有符号二进制乘积公式:将公式对应推码=a*b=2a*(b/2)——b为偶数=2a*(b-1)/2+a——b为奇数,正数=2a*(b+1)/2-a——b为奇数,负数逻辑:乘数a连续左移,且当b返回0时,乘数b不断右移,a左移累加的值就是乘积之和。图11.乘法运算(无符号)publicintmultiplyUnsigned(intnumber1,intnumber2){intresult=0;int乘数=number2;intbitIdx=0;while(multiplier!=0){if((multiplier&1)==1){System.out.println(number1+"<<"+bitIdx+"="+(number1<>1;}returnresult;}目的:计算无符号二进制乘积公式:13=2^3+2^2+2^0x*13=x*2^3+x*2^2+x*2^0x*13=x<<3+x<<2+x<<02*13=2<<3+2<<2+2<<0=16+8+2=26逻辑:每个数都可以表示为一系列的和2的幂次方。例如13的二进制值为1101,右首位为1,为2的0次方,所以对应的二进制值2左移0位.再比如,13右边的数第三位是1,对应的位置值为4,是2的次方,所以2对应的基数左移2位。最后将这些值相加,形成产品值。12.1publicintcountSetBits(intoriginalNumber){intsetBitsCount=0;intnumber=originalNumber;while(number!=0){setBitsCount+=number&1;数>>>=1;}returnsetBitsCount;}目的:使用位运算符统计一个数中设置为1的位。逻辑:每次将数字向右移动一位,然后用&运算符取出最右边位的值,计数加1。0被忽略。13.转换计算publicintbitsDiff(intnumber1,intnumber2){returncountSetBits(number1^number2);}目的:计算一个数并转换为另一个数,转换需要的位数。逻辑:当一个数字被异或时,结果将是不同位的数量(即在异或的结果中所有位设置为1的数量)。14.有效数字publicintbitLength(intnumber){intbitsCounter=0;while((1<