源我的答案:整数除以7
Is this expression correct in C preprocessor
我一点点我的长处在这里,我试图理解这个特定的优化工作。
正如答复中提到,GCC将通过7优化整数除法:
mov edx, -1840700269
mov eax, edi
imul edx
lea eax, [rdx+rdi]
sar eax, 2
sar edi, 31
sub eax, edi
它转换回C作为:
int32_t divideBySeven(int32_t num) {
int32_t temp = ((int64_t)num * -015555555555) >> 32;
temp = (temp + num) >> 2;
return (temp - (num >> 31));
}
让我们先来看看第一部分:
int32_t temp = ((int64_t)num * -015555555555) >> 32;
为什么这个数字?
那么,让我们取2^64并除以7,看看弹出了什么。
2^64/7 = 2635249153387078802.28571428571428571429
这看起来像一团糟,如果我们把它转换成八进制呢?
0222222222222222222222.22222222222222222222222
这是一个非常漂亮的重复模式,肯定不能是巧合。我的意思是我们记得7是0b111
,我们知道当我们除以99时,我们倾向于获得基数为10的重复模式。因此,当我们除以7时,我们将在基数8中得到重复模式。
那么我们的号码进来了吗?
(int32_t)-1840700269
相同(uint_32t)2454267027
* 7 = 17179869189
最后17179869184是2^34
这意味着17179869189为7 2^34最接近的倍数。或者换一种说法2454267027是,将适合在uint32_t
,当乘以7非常接近的2
什么是八进制这个数字电源数量最多?
0222222222223
为什么这很重要?那么,我们要除以7.这个数字大约是2^34/7 ...。所以如果我们乘以它,然后移位34次,我们应该得到一个非常接近确切数字的数字。
最后两行看起来像是为修补近似误差而设计的。
也许有人在这方面有更多的知识和/或专业知识可以在这方面作出贡献。
>>> magic = 2454267027
>>> def div7(a):
... if (int(magic * a >> 34) != a // 7):
... return 0
... return 1
...
>>> for a in xrange(2**31, 2**32):
... if (not div7(a)):
... print "%s fails" % a
...
故障开始在3435973841这是有趣的是0b11001100110011001100110011010001
判断为什么逼近失败是有点超出我,为什么补丁修复它是为好。有谁知道魔法如何超越我在这里放下的东西?
http://www.hackersdelight.org/divcMore.pdf – 2013-03-07 03:21:12
该pdf对于确定最后一行是什么非常有用(标记修复);但是,除非我错过了它,否则似乎没有特别讨论这种算法。 – OmnipotentEntity 2013-03-07 03:36:41
明确的参考文献是[here](http://gmplib.org/~tege/divcnst-pldi94。pdf)(在gcc编译器中实现)和后续[here](http://gmplib.org/~tege/division-paper.pdf)。实现可以在[GMP](http://gmplib.org/)库中找到。 ('gmp-impl.h'中的'udiv_qrnnd_preinv') – 2013-03-07 08:25:35