使用按位运算符划分
我在stackoverflow上发现了一篇帖子
看到这个奇怪的方法除以3(What's the fastest way to divide an integer by 3?)
它说: n / 3 =(n * 0x55555556)>> 32 即可。这将乘以 0x55555556 并取最重要的32位。对于n为32位的数字,这是正确的。
当我开始挖掘它背后的逻辑时,我意识到这可以推广。例如,如果我们认为n< 128;即,7位宽,然后: n / 3 =(n * 0x56)>> 8 即可。
那么这里发生了什么?好吧, 0x56 = 86 =(258/3), 258 是第一个大于256的数字,可以被3整除。现在,
2n = 258n - 256n
= => n = 129n - 128n 对于任何n;
但是如果限制n< 128;然后129n - 128n与(129n / 128)的商相同
==> n = 129n / 128 ; n< 128个
==> n / 3 = 43n / 128 ;对于n< 128个
==> n / 3 = 86n / 256 ; n< 128个
==> n / 3 =(n * 0x56)>> 8 ;
令人惊讶的是,这可以推广到其他部门。例如,考虑除以5:
4n = 260n - 256n ==>所有n的 n = 65n - 64n
如果 n< 64; n = 65n / 64
==> n / 5 = 13n / 64 ; n< 64个
==> n / 5 =(13 * n)>> 6 ;
类似地, n / 5 =(52 * n)>> 8 ; n< 64个
我们可以继续沿着同样的路线前进: n / 5 = 205n / 1024 =(205 * n)>> 10 对于n< 1024
因此;我试图找到一条通用规则,为任何 a 找到不适用?
首先找到两个幂(比如 2 ^ m ),它是a的倍数的一个(如果a = 5则为1024);
即 2 ^ m + 1 = k a ;对于一些k
所以工作就是找出 k ,同时保持 m 固定(比如32): 2 ^ m + 1 = k 的一个即可。可以有多种解决方案;一旦 m 被修复,将只有一个。
然后; n / a = k * n>>米;对于所有n< 2 ^ M
现在这是编译器的工作方式吗?在其中一条评论中使用 kol 提供的formula generator:
保持m = 32和n = 12;公式生成器给出:
a = 3: n / 3 =(1431655766 * n)>> 32
a = 5: n / 5 =(858993460 * n)>> 32
a = 7: n / 7 =(613566757 * n)>> 32
然而,当我看到我的装配输出时,我分别得到 1431655766 , 1717986919 和 -1840700269 除以3,5和7。
此外,如果我将数据类型更改为unsigned int,那么对于3,5和7,我分别得到 -1431655765 , -858993459 和 613566757 。
var $a = $("#a"),
$m = $("#m"),
$generate = $("#generate"),
$formula = $("#formula");
$generate.click(function () {
var a = +$a.val(),
m = +$m.val(),
m2 = 0,
k = 0;
if (isNaN(a) || a !== Math.floor(a) || a < 2 || a > Math.pow(2, 31) - 1) {
alert("Divisor \"a\" must be an integer between 2 and 2^32-1");
return;
}
m2 = Math.pow(2, m);
k = Math.ceil(m2 / a);
$formula.html("<i>n</i> / " + a + " = (" + k + " * <i>n</i>) >> " + m + "; for all <i>n</i> < " + m2);
});
$generate.click();
答案 0 :(得分:2)
不,C编译器不会通过按位操作进行arithemetics。即使在装配过程中,也不必按位操作进行化验。当然,它在处理器上以这种方式工作,并且处理器提供这里描述的命令:http://en.wikibooks.org/wiki/X86_Assembly/Arithmetic作为这些操作的抽象。