简单的问题是,是否可以通过更便宜的操作来简化(或替换除法或模数)
(k/m)%n
其中变量是整数,运算符是C样式除法和模运算符。
让我稍微重新解释一下问题,除了变量是base2的情况,在什么条件下(例如某些变量可能是常数)可以简化表达式(或者使用base2操作部分重新表达)来删除除法或模数?
这是我学习数论的方法,特别是base2技巧,而不是在性能优化中练习
谢谢
答案 0 :(得分:3)
对于任意精度整数,我建议查看http://documents.epfl.ch/users/k/ka/kaihara/www/papers/ModMulDiv_Binary.pdf
它提供了一种硬件方法,但它提供了可以适应的伪代码。
答案 1 :(得分:3)
明显的优化:
k % m
。0
。(k >> 2) % n
; (k / m) & (n - 1)
; 检查#1和#2是微不足道的。
使用以下方法检查2的权力:
void isPowerOfTwo(unsigned int x)
{
return x & (x - 1) == 0;
}
答案 2 :(得分:3)
对于具有小常数分母的除法,您可以使用类似的东西。
k/m=k*(1/m)
x=(1<<16)/m
k/m=(k*x)>>16
根据输入,答案可能不准确。
对于具有小奇数常数分母的除法,您可以使用multiplicative inverse。以下常量适用于32位除法。
3 2863311531 11 3123612579
5 3435973837 13 3303820997
7 3067833783 15 4008636143
9 954437177 17 4042322161
x/11 == x*3123612579 % 2^32
% 2^32
当然在32位整数上是免费的。采用这个偶数来分解两个并在以后应用它们。
x/44 == (x*3123612579 % 2^32) >> 2
Hackers Delight有一章关于整数除法。
两个幂的简单模数和除法。
x%m == x&(m-1)
x/m == x>>log2(m) // assumes log2(m) is known, not calculated
答案 3 :(得分:1)
加入Peter Alexander的回答
0)当然m!= 0&amp;&amp; n!= 0是前提条件......
1)k&lt; m:答案总是0
2)k == m:答案总是1(除非n也是1,见5)。
3)k / m < n:答案是k / m
4)k&lt; (m * n):答案总是k / m。 由于m * n,这种特殊条件不太有利于优化 不会被重用,它不应该比模数快得多 除非m和/或n是2的幂,否则你仍然可以更好地使用 7.和/或8.
参考添加彼得亚历山大:
5)m == 1:答案只是k%n。
6)n == 1:答案总是为0。
7)m是2的幂:例如如果m为4,则可以使用(k>&gt;&gt; 2)%n;
8)n是2的幂:表达式变为(k / m)&amp; (n - 1);
答案 4 :(得分:0)
我认为这取决于。 一个正确的算术移位会让你除以2,并且通过一些额外的算术,你可以将它划分为任何数字的除法。 同样地,我认为你可以对模运算符做同样的事情。 实际上,除非你的处理器缺少必要的硬件,否则我不会想到你会获得任何东西。
修改的 实际上在考虑这个问题时,严格来说需要更多的思考,对于负数,签名班次不能作为2的除法。
如果我没记错的话,算术右移的行为在负数的C标准中是未定义的(它涉及2的幂),因此依赖于编译器。
如果我们只是考虑数论的逻辑那么那就是另一回事了。让我考虑一下。