使用x64 / sse上的向量指令计算x%M的最佳/最快方法是什么? (以%表示mod /余数)。
我无法找到打包mod的任何操作码,所以我认为我能做的最好是将int提升为浮点数,然后使用DIVPS和ROUNDPS计算x - m * floor(x / m)。
还是有一个更好的替代品,我错过了吗?
UPDATE :M仅在运行时已知,实际循环如下所示:
unsigned x[SIZE], M[SIZE], answer[SIZE];
for (int i = 0; i < SIZE; i++) {
answer[i] = x[i] % M[i];
}
如果M以任何方式有帮助,那么M已知在1 - 640000000范围内。
答案 0 :(得分:3)
如果M
是编译时常量或在循环内是常量,那么您可以calculated a reciprocal and then do multiplication and a shift而不是使用除法。我们可以写
x/M = (x*(2^n/M))>>n
因子2^n/M
(又名magic number)应该在循环之前或编译时计算。
例如,如果我们想要x[i]/5
并且我们知道x[i]
小于2^15
,我们可以使用2^n/M = 0xCCCD
和n = 18
。
#include <stdio.h>
#define N 32768
int x[N], y[N], z[N];
int main(void) {
for(int i=0; i<N; i++) x[i] = i;
int M = 5;
int fact = 0xCCCD;
int n = 18;
for(int i=0; i<N; i++) {
y[i] = x[i]/M;
z[i] = (fact*x[i])>>n;
if(y[i] != z[i]) printf("%d %d\n", y[i], z[i]);
}
}
有几种不同的方法可以确定幻数和n
。我使用Agner Fog's Vector Class Library(VCL)。它使用SSE2或AVX2为32位数字(而不是上面代码中的15位数字)为您执行此操作。如果你想看到汇编代码来执行此操作,他的assembly library也会为SSE2(也许是AVX2)执行此操作
有关详细信息,请参阅VCL手册的第22页。它在装配库的手册中也有描述。