为什么按位除法不像按位乘法那样工作?

Why bitwise division does not work like bitwise multiplication?

假设我只想使用位移来计算 20*10=200。这可以通过

轻松完成
a = 20<<3 // 2^3
b = 20<<1 // 2^1
a + b // Result is 200.

现在,为什么我尝试对除法做同样的事情却得到错误的结果?例如,如果我尝试计算 200/10

#include <stdio.h>

int main() {

    int value = 200;
    int a = value >> 3;
    int b = value >> 1;

    printf("200/10 is %d\n", (a+b));

    return 0;
}

我得到一个125?我做错了什么?

这里的评论很好地解释了为什么这不起作用。这里详细说明了为什么乘法有效,为什么除法无效。

让我们从乘法开始。假设您要计算 200 × 10。您可以通过评估 200 × (9 + 1) 或 200 × (8 + 2) 等来计算。这些表达式中的每一个都等同于原始表达式。使用分配式 属性,这意味着我们可以计算 200 × 9 + 200 × 1 得到 200 × 10,或者我们可以计算 200 × 8 + 200 × 2 得到 200 × 10,等等

碰巧通过位移位更容易乘以 2 的幂。因此,例如,我们可以通过评估

来计算 200 × 10
200 x 10 = 200 x (8 + 2)
         = 200 x 8  +  200 x 2
         = (200 << 3) + (200 << 1)

现在,我们可以这样做除法吗?好吧,200 / 10 = 200 / (8 + 2) 确实是真的,和以前一样。但与乘法不同的是,在 200 / (8 + 2) 的情况下,我们没有分配式 属性,因此我们无法重写

200 / (8 + 2) = (200 / 8) + (200 / 2).

因此,我们不能使用反向移位技术来快速进行除法。

我认为效率在这里不是问题,它只是为了好玩(或作业?)。

如前所述,通过移位除以 10 不像乘以 10 那样容易。

但是,对于这样的除法,很可能使用位移位,只是需要更多的位移。

例如,我们可以使用 1/10 = 1/8 - 1/10 (1/4)

输出:

3/10 = 0
12/10 = 1
128/10 = 13
1465/10 = 147
4566/10 = 457
5674/10 = 567
#include <stdio.h>
int div10 (int n) {
    if (n == 0) return 0;
    return (n >> 3) - div10(n >> 2);
}

int main () {
    int nums[] = {3, 12, 128, 1465, 4566, 5674};
    int n = sizeof(nums)/ sizeof(nums[0]);
    for (int i = 0; i < n; ++i) {
        int num = nums[i];
        int ans = div10(num);
        printf ("%d/10 = %d\n", num, ans);
    }
    return 0;
}

您得到了很好的答案,但请允许我提供另一种可能更简单的观点。这是乘法:

a = 20<<3 
b = 20<<1 
a + b 

你想这样除法:

a = 20>>3 
b = 20>>1 
a + b 

这里的问题是你只颠倒了个别部分。你需要扭转整个过程。让我们以温度为例。如果你有一个特定的摄氏温度 c 并想将其转换为华氏温度,你可以使用以下公式:

f = 1.8c + 32

您正在尝试使用相同的公式转换回摄氏度:

c = f/1.8 - 32

但是由于加法是原始公式的最后一步,我们需要在 反转乘法之前 反转该步骤。这是正确的反转:

c = (f-32)/1.8