位运算实现加减乘除

Posted by Marlin on August 5, 2025

位运算实现加减乘除

前提:位运算实现加减乘除,过程中不能出现任何算数运算符。

加法

利用每一步无进位相加的结果+进位的结果不停计算,直到进位消失。

1
2
3
4
5
6
7
8
9
int add(int a, int b){
    int ans = a; // a和b无进位相加的结果
    while(b != 0){ // 进位信息不为0时循环
        ans = a ^ b;
        b = (a & b) << 1; // a和b相加时的进位信息
        a = ans;
    }
    return ans;
}

减法

利用加法,和一个数字x相反数就是(~x) + 1(按位取反后加一)。

1
2
3
int subtract(int a, int b){
    return add(a, add(~b, 1));
}

乘法

回想小学时候怎么学的乘法,除此以外没别的了。

1
2
3
4
5
6
7
8
9
10
11
12
int multiply(int a, int b) {
    int ans = 0;
    unsigned int u_b = b; // 转为无符号处理右移
    while (u_b != 0) {
        if (u_b & 1) {
            ans = add(ans, a);
        }
        a <<= 1;
        u_b >>= 1; // 无符号右移(自动补零)
    }
    return ans;
}

除法

为了防止溢出,让被除数右移,而不是除数左移。从高位尝试到低位。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// 必须保证a和b都不为整数最小值
int div(int a, int b) {
    // 使用无符号处理绝对值
    unsigned int x = a < 0 ? (unsigned int)(~a) + 1 : a;
    unsigned int y = b < 0 ? (unsigned int)(~b) + 1 : b;
    int ans = 0;
    
    // 从31位开始检测
    for(int i = 31; i >= 0; i = subtract(i, 1)) {
        if((x >> i) >= y) {
            ans |= (1 << i);
            x = subtract(x, y << i);
        }
    }
    return (a < 0) ^ (b < 0) ? -ans : ans;
}
int divide(int a, int b){
    if(a == INT_MIN && b == INT_MIN){
        return 1;
    }
    if(a != INT_MIN && b != INT_MIN){
        return div(a, b);
    }
    if(b == INT_MIN){
        return 0;
    }
    if(b == -1){ // a是整数最小,b是-1,返回INT_MAX,题目明确这么说了
        return INT_MAX;
    }
    a = add(a, b > 0 ? b : -b);
    int ans = div(a, b);
    int offset = b > 0 ? -1 : 1;
    return add(ans, offset);
}