为什么按位除法不像按位乘法那样工作?
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
假设我只想使用位移来计算 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 × 10200 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