代码如下:
package class05;
/**
* 位运算实现 + - * /
* 手写的 + - * / 不如 java自带的+ - * / 快, 这是当然了,你自己写一个方法去实现,肯定不如人家一条语句快
* i>>6 肯定比 i/64 要快, i & 63 肯定要比 i % 64 要快
*
* 其它知识点:
* 位运算基本操作,按位与,按位或,按位异或,左移,右移等, 怎样利用这些操作去实现 + - * / % 这5个操作???
* 异或运算,在位运算看来就是无进位相加, 任何一位相加之后产生的进位都抛弃。
* 怎样得到进位信息? 按位与之后,整体左移 1 位
*/
// 测试链接:https://leetcode.com/problems/divide-two-integers 力扣原题,也得做一下
public class Code03_BitAddMinusMultiDiv {
/**
* 1.异或操作 相当于两个数相加,但是每一位相加后,都忽略进位
* 2.按位与之后左移 1 位, 相当于拿到了每一位相加后的进位值。(进位补偿值)
* 上面的二者相加就是最终的结果,但是不能直接相加,因为不能直接使用+ 运算符,那么怎么把这两个值相加呢?
* 上面得出的两个值,再继续进行 异或操作 和 按位与之后左移1位操作,循环执行这个过程,直到进位补偿信息变为0,
* 那么就结束了。
* @param a
* @param b
* @return
*/
//加法, a + b
public static int add(int a, int b) {
int sum = a;
while (b != 0) {
sum = a ^ b;
b = (a & b) << 1;
a = sum;
}
return sum;
}
//相反数(不是取反): 相反数是取反之后 + 1, 我们这里用add实现
//整数取反之后,其最高位变为1,表示负数。同理,负数取反之后,变为正数
public static int negNum(int n) {
return add(~n, 1);
}
//减法, 等于 a + (-b)
public static int minus(int a, int b) {
return add(a, negNum(b)); //将b取 相反数(不是取反,别搞错了),相反数 = 取反 + 1, 取反可以把正数变为负数
}
//乘法, 跟十进制数字相乘的算法是一致的。
public static int multi(int a, int b) {
int res = 0;
while (b != 0) {
if ((b & 1) != 0) {
res = add(res, a);
}
a <<= 1; // a要左移1位,相当于补了1个0(每次循环都要补0)
b >>>= 1; //让b不断右移
}
return res;
}
//判断是否为负数
public static boolean isNeg(int n) {
return n < 0;
}
//除法
public static int div(int a, int b) {
int x = isNeg(a) ? negNum(a) : a;
int y = isNeg(b) ? negNum(b) : b;
int res = 0;
for (int i = 30; i >= 0; i = minus(i, 1)) {
if ((x >> i) >= y) {
res |= (1 << i);
x = minus(x, y << i);
}
}
return isNeg(a) ^ isNeg(b) ? negNum(res) : res;
}
//除法
public static int divide(int a, int b) {
if (a == Integer.MIN_VALUE && b == Integer.MIN_VALUE) {
return 1;
} else if (b == Integer.MIN_VALUE) {
return 0;
} else if (a == Integer.MIN_VALUE) {
if (b == negNum(1)) {
return Integer.MAX_VALUE;
} else {
int c = div(add(a, 1), b);
return add(c, div(minus(a, multi(c, b)), b));
}
} else {
return div(a, b);
}
}
public static void main(String[] args) {
int a = 7;
int b = -3;
//乘法为什么支持b为负数,这个很难解释,跟补码有关,这里就不解释了
System.out.println(multi(a,b)); //-21
//正常取模
int i = 11;
int result = i % 10;
System.out.println(result);
/**
* 通过 1 次位运算实现取模,能不能够实现? 可以实现,但是实在某些特定条件下,什么特定条件?? 对谁取模, 只有对2^n取模的时候,
* 才能使用1次位运算实现取模。所以这里对10取模,是不能通过1次位运算实现的。
*/
/**
* 10: 000000000 00000000 00001010
* 11: 000000000 00000000 00001011
*
*/
int result1 = i & 9;
System.out.println(result1);
/**
* 对64进行取模运算, 64 = 2^6, 可以通过1次位运算来实现。
* 63: 00000000 00000000 00111111 32+16+8+4+2+1 = 63
* 与63进行按位与,在1区域左侧的数据,都被抹掉了,剩下的值就是取模的值
*/
int result2 = 65 & 63;
System.out.println(result2);
}
}
乘法原理如下:
与普通整数之间的乘法是一致的。
除法原理如下: