一、位运算相关规律+口诀
二、加减乘除
int add(int num1, int num2){
int temp;
do {
temp = num1 ^ num2;//不进位相加:异或
num2 = (num1 & num2) << 1;//进位:位与+左移
num1 = temp;
} while(num2!=0);
return num1;
}
//num1为被减数,num2为减数
int substract(int num1, int num2){
int subtractor = add(~num2, 1);//负数:取反加1
int result = add(num1, subtractor);
return result ;
}
1、1110&1,最后1位=0,所以结果=0;被乘数1101左移1位=11010,乘数1110右移1位=0111; 2、0111&1,最后1位=1,所以结果=11010;被乘数11010左移1位=110100,乘数0111右移1位=0011; 3、0011&1,最后1位=1,所以结果=11010+110100=1001110;被乘数110100左移1位=1101000,乘数0011右移1位=0001; 4、0001&1,最后1位=1,所以结果=1001110+1101000=10110110;被乘数110100左移1位=11010000,乘数0011右移1位=0 乘数=0,循环结束。 | (1) 判断乘数是否为0,为0跳转至步骤(4) (2) 将乘数与1作与运算,确定末尾位为1还是为0,如果为1,则相加数为当前被乘数;如果为0,则相加数为0;将相加数加到最终结果中; (3) 被乘数左移一位,乘数右移一位;回到步骤(1) (4) 确定符号位,输出结果; |
//multiplicand被乘数,multiplier乘数,product乘积
int multiply(int a, int b) {
//将乘数和被乘数都取绝对值
int multiplicand = a < 0 ? add(~a, 1) : a;
int multiplier = b < 0 ? add(~b , 1) : b;
//计算绝对值的乘积
int product = 0;
while(multiplier > 0) {
if((multiplier & 0x1) > 0) {// 每次考察乘数的最后一位
product = add(product, multiplicand);
}
multiplicand = multiplicand << 1;// 每运算一次,被乘数要左移一位
multiplier = multiplier >> 1;// 每运算一次,乘数要右移一位(可对照上图理解)
}
//计算乘积的符号
if((a ^ b) < 0) {
product = add(~product, 1);
}
return product;
}
计算机是一个二元的世界,所有的int型数据都可以用[2^0, 21,...,231]这样一组基来表示(int型最高31位)。不难想到用除数的231,230,...,22,21,2^0倍尝试去减被除数,如果减得动,则把相应的倍数加到商中;如果减不动,则依次尝试更小的倍数。这样就可以快速逼近最终的结果。2的i次方其实就相当于左移i位,为什么从31位开始呢?因为int型数据最大值就是2^31
//dividend被除数,divisor除数,quotient商,remainder余数
int divide_v2(int a,int b) {
// 先取被除数和除数的绝对值
int dividend = a > 0 ? a : add(~a, 1);
int divisor = b > 0 ? a : add(~b, 1);
int quotient = 0;// 商
int remainder = 0;// 余数
for(int i = 31; i >= 0; i--) {
//比较dividend是否大于divisor的(1<<i)次方,不要将dividend与(divisor<<i)比较,而是用(dividend>>i)与divisor比较,
//效果一样,但是可以避免因(divisor<<i)操作可能导致的溢出,如果溢出则会可能dividend本身小于divisor,但是溢出导致dividend大于divisor
if((dividend >> i) >= divisor) {
quotient = add(quotient, 1 << i);
dividend = substract(dividend, divisor << i);
}
}
// 确定商的符号
if((a ^ b) < 0){
// 如果除数和被除数异号,则商为负数
quotient = add(~quotient, 1);
}
// 确定余数符号
remainder = b > 0 ? dividend : add(~dividend, 1);
return quotient;// 返回商
}
三、判断整数number是否是2的乘方
bool isPower(int number) {
return (number & number - 1) == 0;
}
四、判断正整数转换成二进制后的数字“1”的个数
//乘方:n&(n-1)可以把整数二进制的最右边的数由1变为0
int bitCount1(int n) {
int count = 0;
while (n != 0) {
n = n & (n - 1);
count++;
}
return count;
}
//移位: 二进制与1进行&运算的时候,当最末位也就是最右边的一位为1的时候,结果就是1,
//判断完最后一位,然后把整数的二进制右移一位,再判断,直到整数等于 0 结束循环
int bitCount2(int n) {
int count = 0;
while (n > 0) {
if ((n & 1) == 1) count++;//如果最右边的值是1
n >>= 1; //向右一位
}
return count;
}
//可忽略。分治法,详见:https://www.jianshu.com/p/d8a0c6299dab
int bitCount3(int i) {
i = i - ((i>>>1) & 0x55555555);
i = (i & 0x33333333) + ((i>>>2)&0x33333333);
i = (i+(i>>>4)) & 0x0f0f0f0f;
i = i + (i>>>8);
i = i + (i>>>16);
return i & 0x3f;
}
转载:加减乘除