高效的Modulo 3操作?

时间:2011-11-15 19:13:10

标签: java c++ c performance modulo

  

可能重复:
  Fast modulo 3 or division algorithm?

每个人都知道模运算可能是性能上的一个巨大缺点。有没有人知道x%3操作的好选择?我知道x%2存在一个,但我真的需要一个模3,因为我想在for循环中在三个缓冲区之间交替。

谢谢!

3 个答案:

答案 0 :(得分:10)

而不是通常的“衡量它”是一个真正的答案 - 因为那些东西实际上是真正有趣的数学。虽然编译器可以并且也可能这样做(至少现代优化c ++编译器,javac肯定不会,我不知道JVM是否这样做) - 所以最好检查它是否还没有完成工作你。

但是知道优化背后的理论仍然很有趣:我将使用汇编,因为我们需要乘法的32位字。以下内容来自沃伦关于比特小说的书:

n是我们想要模数的输入整数:

li M, 0x55555556   ; load magical number (2^32 + 2) / 3
mulhs q, M, n      ; q = higher word of M * n; i.e. q = floor(M*n / 2^32)
shri t, n, 31      ; add 1 to q if it is negative
add q, q, t

这里q包含n / 3的除数,所以我们像往常一样计算余数:r = n - q*3

数学是有趣的部分 - 乳胶在这里会很酷:

q =楼层((2 ^ 32 + 2)/ 3 *(n / 2 ^ 32))=楼层(n / 3 + 2 * n /(3 * 2 ^ 32))

现在,对于n = 2 ^ 31-1(对于带符号的32位整数,最大n可能),误差项小于1/3(并且非负),这使得很容易证明结果确实是正确的。对于n = -2 ^ 31,我们有上面的校正1,如果你简化,你会发现误差项总是大于-1/3,这意味着它也适用于负数。

我将证据留给感兴趣的错误术语界限 - 这并不难。

答案 1 :(得分:6)

如果是直线循环,则无需计算模数。保持第二个int var,每3步重置一次。

int i, bn = 0;

for(i=0; i<whatever; i++) {
  ...
  if(++bn == 3) bn = 0;
}

这不是一个不成熟的优化,它避免了不必要的计算。

编辑:在OP中声明他使用循环在缓冲区之间切换,所以我的解决方案看起来非常合适。 至于downvote,如果是一个错误,没问题。

答案 2 :(得分:5)

如果在编译时知道3,那么编译器将生成“技巧”以尽可能高效地完成。当除数在运行时未知时,模数需要更长的时间。