有没有办法,如何比使用“%”运算符快511(和127)模数?
int c = 758 % 511;
int d = 423 % 127;
答案 0 :(得分:0)
您可以使用预先存储的解决方案的查找表。如果你创建一个包含一百万个整数的数组,那么查找速度大约是我在C#app中实际模数的两倍。
// fill an array
var mod511 = new int[1000000];
for (int x = 0; x < 1000000; x++) mod511[x] = x % 511;
而不是使用
c = 758 % 511;
你使用
c = mod511[758];
这将花费你(可能很多)内存,如果你想将它用于非常大的数字,显然也不会有效。但它更快。
答案 1 :(得分:0)
如果你必须对大量数据重复这两个模数运算,并且你的CPU支持SIMD(例如Intel的SSE / AVX / AVX2),那么你可以对操作进行矢量化,即对许多数据进行并行操作。您可以使用内在函数或内联汇编来完成此操作。是的,解决方案将是特定于平台的,但也许这很好......
答案 2 :(得分:0)
这是一种快速模数为511的方法,假设x最多为32767.它的速度大约是x%511
的两倍。它以五个步骤进行模数:两次乘法,两次加法,一次移位。
inline int fast_mod_511(int x) {
int y = (513*x+64)>>18;
return x - 511*y;
}
以下是我如何达成这一目标的理论。我在最后发布了我测试过的代码
让我们考虑一下
y = x/511 = x/(512-1) = x/1000 * 1/(1-1/512).
让我们定义z = 512,然后
y = x/z*1/(1-1/z).
使用泰勒扩展
y = x/z(1 + 1/z + 1/z^2 + 1/z^3 + ...).
现在,如果我们知道x的范围有限,我们就可以减少扩展。假设x总是小于2 ^ 15 = 32768。然后我们可以写
512*512*y = (1+512)*x = 513*x.
在查看了重要的数字后,我们到达
y = (513*x+64)>>18 //512^2 = 2^18.
我们可以分三步来划分x / 511(假设x小于32768):
multiply,
add,
shift.
以下是我在Ivy Bridge核心上以MSVC2013 64位版本模式对此进行分析的代码。
#include <stdio.h>
#include <stdlib.h>
#include <omp.h>
inline int fast_mod_511(int x) {
int y = (513*x+64)>>18;
return x - 511*y;
}
int main() {
unsigned int i, x;
volatile unsigned int r;
double dtime;
dtime = omp_get_wtime();
for(i=0; i<100000; i++) {
for(int j=0; j<32768; j++) {
r = j%511;
}
}
dtime =omp_get_wtime() - dtime;
printf("time %f\n", dtime);
dtime = omp_get_wtime();
for(i=0; i<100000; i++) {
for(int j=0; j<32768; j++) {
r = fast_mod_511(j);
}
}
dtime =omp_get_wtime() - dtime;
printf("time %f\n", dtime);
}