如果您的 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
不在整数范围之外)。您甚至可以在一个循环8*b
之前插入更多循环(比如一个)4*b
以提高速度。
除此之外,手动编码汇编器可能会有所帮助,但我认为如果没有它,您会从上面的代码中找到相当大的提升。
如果您了解有关使用 mod 调用方式的更多详细信息,则可以针对您的特定情况对其进行优化。例如,如果您只想知道 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 秒与 0 秒)。直到那时,它们都是 0 秒,尽管它是在快速机器上运行的(对 更好)mod25
并且有div
指令(对%
操作员更好),所以你需要在你自己的硬件上对其进行基准测试。
在不使代码不可读的情况下,这几乎是您可能获得的最快速度(尽管如果您愿意添加大量注释来解释它是如何工作的,即使这样也不应该阻止您)。
对于任何分母,一个更通用的解决方案是首先将分母加倍(为了速度而进行位移),以使随后的减法最小化。然后,当分子减少到低于增加的分母时,将分母减半并继续前进(直到分母回到起点)。
int mod (int n, int d) {
/* dx is the adjusted denom, don't let it overflow though. */
int dx = d;
while (((dx << 1) >>1) == dx)
dx <<= 1;
/* This loop processes the dx values until they get too small. */
while (dx >= d) {
/* This loop subtracts the large dx value. */
while (n >= dx)
n -= dx;
dx >>= 1;
}
return n;
}
这实际上与上述优化版本的性能相当,mod25
同时提供了更通用的解决方案。