32.【必备】位运算实现加减乘除
·
本文的网课内容学习自B站左程云老师的算法详解课程,旨在对其中的知识进行整理和分享~
一.两数相除
题目:两数相除
算法原理
-
整体思路
- 这个算法旨在仅使用位运算来实现整数的加、减、乘、除操作。通过巧妙地利用位运算的特性,如异或(无进位相加)、与(获取进位)、移位(乘以或除以2的幂次方)等操作来模拟算术运算。
-
具体原理
- 加法(
add方法)- 利用异或操作实现无进位相加:
ans = a ^ b。异或操作在两个对应位不同时结果为1,相同为0,这类似于不考虑进位的加法。 - 利用与操作获取进位并左移1位:
b = (a & b) << 1。与操作得到的是两个数相加时产生进位的位置,左移1位就是将进位加到下一位。 - 重复上述步骤直到进位
b为0,此时ans就是a和b相加的结果。
- 利用异或操作实现无进位相加:
- 减法(
minus方法)- 基于加法和取反操作实现减法,根据数学原理
a - b=a+( - b),所以调用add方法并传入a和neg(b)来实现减法操作。
- 基于加法和取反操作实现减法,根据数学原理
- 取反(
neg方法)- 先对整数
n按位取反~n,然后再加上1就实现了取反操作。这是基于计算机中负数的表示方法(补码表示),补码就是原码按位取反再加1。
- 先对整数
- 乘法(
multiply方法)- 采用类似于手动计算乘法的方法,从最低位开始逐位处理。
- 如果
b的最低位为1((b & 1)!= 0),就将a加到结果ans中,这相当于在做乘法时,如果乘数的某一位是1,就加上被乘数乘以对应的权值(2的幂次方)。 - 然后
a左移1位(a <<= 1),相当于被乘数乘以2;b右移1位(b >>>= 1),相当于乘数除以2。 - 重复上述步骤直到
b为0,此时ans就是a和b相乘的结果。
- 除法(
divide方法)- 特殊情况处理:
- 如果
a和b都是整数最小值,根据题目要求返回1。 - 如果
b是整数最小值,而a不是,结果为0。 - 如果
a是整数最小值,b是 - 1,按照要求返回整数最大值。
- 如果
- 对于
a和b都不是整数最小值的情况(调用div方法):- 首先将
a和b转换为正数(如果是负数就调用neg方法取反)。 - 从最高位(30位,对于32位整数)开始,逐位判断。如果
x(a转换后的正数)右移i位后的值大于等于y(b转换后的正数),则商的第i位为1,并更新x的值(减去已经计算的部分,即y乘以2的i次方)。 - 根据
a和b的正负情况,对结果进行调整(如果一正一负则取反)。 - 如果
a是整数最小值,b不是整数最小值且不是 - 1,先将a调整为可以正常进行div函数计算的数,然后计算div,最后对结果进行调整并返回。
- 首先将
- 特殊情况处理:
- 加法(
代码实现
// 不用任何算术运算,只用位运算实现加减乘除
// 代码实现中你找不到任何一个算术运算符
// 测试链接 : https://leetcode.cn/problems/divide-two-integers/
// 定义一个类,类名为BitOperationAddMinusMultiplyDivide
public class BitOperationAddMinusMultiplyDivide {
// 定义一个常量MIN,表示整数的最小值
public static int MIN = Integer.MIN_VALUE;
// 除法函数,用于计算a除以b的结果
public static int divide(int a, int b) {
// 如果a和b都是整数最小值,根据题目要求返回1
if (a == MIN && b == MIN) {
return 1;
}
// 如果a和b都不是整数最小值,调用div函数进行正常的除法计算
if (a!= MIN && b!= MIN) {
return div(a, b);
}
// 如果b是整数最小值,而a不是,根据除法规则,结果为0
if (b == MIN) {
return 0;
}
// 如果a是整数最小值,b是 - 1,按照题目要求返回整数最大值
if (b == neg(1)) {
return Integer.MAX_VALUE;
}
// 如果a是整数最小值,b不是整数最小值且不是 - 1
// 先将a调整为可以正常进行div函数计算的数
a = add(a, b > 0? b : neg(b));
int ans = div(a, b);
int offset = b > 0? neg(1) : 1;
// 最后对结果进行调整并返回
return add(ans, offset);
}
// 这个函数用于在a和b都不是整数最小值的情况下进行除法计算
public static int div(int a, int b) {
// 如果a是负数,将其转换为正数(通过neg函数取反)
int x = a < 0? neg(a) : a;
// 如果b是负数,将其转换为正数(通过neg函数取反)
int y = b < 0? neg(b) : b;
int ans = 0;
// 从最高位(30位,对于32位整数来说)开始,逐位判断并计算商
for (int i = 30; i >= 0; i = minus(i, 1)) {
// 如果x右移i位后的值大于等于y
if ((x >> i) >= y) {
// 则商的第i位为1
ans |= (1 << i);
// 更新x的值,减去已经计算的部分(y乘以2的i次方)
x = minus(x, y << i);
}
}
// 根据a和b的正负情况,对结果进行调整(如果一正一负则取反)
return a < 0 ^ b < 0? neg(ans) : ans;
}
// 加法函数,通过位运算实现加法
public static int add(int a, int b) {
int ans = a;
// 当b不为0时,表示还有进位需要处理
while (b!= 0) {
// ans为a和b无进位相加的结果(异或操作实现无进位相加)
ans = a ^ b;
// b为a和b相加时的进位信息(与操作得到进位,再左移1位)
b = (a & b) << 1;
a = ans;
}
return ans;
}
// 减法函数,通过加法和取反操作实现减法(a - b=a+( - b))
public static int minus(int a, int b) {
return add(a, neg(b));
}
// 取反函数,通过先按位取反再加1的方式实现取反
public static int neg(int n) {
return add(~n, 1);
}
// 乘法函数,通过位运算实现乘法,也称为龟速乘
public static int multiply(int a, int b) {
int ans = 0;
// 当b不为0时,继续计算乘法
while (b!= 0) {
// 如果b的最低位为1(即b为奇数)
if ((b & 1)!= 0) {
// 将a加到结果ans中
ans = add(ans, a);
}
// a左移1位,相当于a乘以2
a <<= 1;
// b右移1位,相当于b除以2
b >>>= 1;
}
return ans;
}
}
更多推荐



所有评论(0)