如何使用SSE计算mod / remainder?

时间:2014-12-19 06:31:37

标签: assembly sse division

使用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范围内。

1 个答案:

答案 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 = 0xCCCDn = 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页。它在装配库的手册中也有描述。