如果您的C编译器的目标CPU没有除法指令,您可以按照以下方式修改代码:
mod(a, b) {
int s = b + b + b + b;
int r = a;
while(r >= s) {
r -= s;
}
while(r >= b) {
r -= b;
}
return r;
}
这种方法是将数值按四个一组相减,直到最后一个,然后切换为每次只减去一个。
这样做可以使您的代码运行速度约快四倍(假设4*b
不超出整数范围)。您甚至可以在4*b
之前插入更多循环(比如8*b
),以获得更快的速度。
除此之外,手写汇编可能会有所帮助,但我认为您会发现上述代码已经有了相当大的提升,无需手写汇编。
如果您对使用模运算的方式有更多细节了解,可以针对特定情况进行优化。例如,如果您只想知道16位整数的模25,下面的代码比具有变量分母的简单循环要快得多。
int mod25 (int a) { // a has maximum value of 2^15-1 = 32767
while (a >= 15625) a-= 15625; // at most 2 times.
while (a >= 625) a-= 625; // at most 24 times.
while (a >= 25) a-= 25; // at most 24 times.
return a;
}
运行一个测试,我发现在使用取模代码和使用
%
操作符之间出现明显差异之前,你必须进行1000万次迭代(2秒 vs. 0秒)。在那之前,它们都是0秒,尽管这是在一台快速的机器上运行的(对于
mod25
更好),并且使用了
div
指令(对于
%
操作符更好),因此你需要在自己的硬件上进行基准测试。
这大概是你能得到的最快速度,而不至于让你的代码难以阅读(尽管即使如此,如果你愿意添加很多解释说明它的工作原理,也不应该阻止你)。
对于任何分母的更通用的解决方案是,首先通过位移将分母加倍,以尽量减少随后的减法。然后,在分子降至增加的分母以下时,将分母减半并继续进行(直到分母回到起点)。
int mod (int n, int d) {
int dx = d;
while (((dx << 1) >>1) == dx)
dx <<= 1;
while (dx >= d) {
while (n >= dx)
n -= dx;
dx >>= 1;
}
return n;
}
实际上,这个更通用的解决方案的性能与上面优化版本的mod25
相当。