Assembly 如何使用SSE计算mod/余数?
在x64/sse上使用矢量指令计算x%M的最佳/最快方法是什么?(我所说的%是指模/余数) 我找不到压缩mod的任何操作码,所以我认为我能做的最好的方法是将int提升为float,然后使用DIVPS和ROUNDPS计算x-m*floor(x/m) 还是有一个更好的选择我错过了 更新:M仅在运行时已知,实际循环如下所示:Assembly 如何使用SSE计算mod/余数?,assembly,sse,division,Assembly,Sse,Division,在x64/sse上使用矢量指令计算x%M的最佳/最快方法是什么?(我所说的%是指模/余数) 我找不到压缩mod的任何操作码,所以我认为我能做的最好的方法是将int提升为float,然后使用DIVPS和ROUNDPS计算x-m*floor(x/m) 还是有一个更好的选择我错过了 更新:M仅在运行时已知,实际循环如下所示: unsigned x[SIZE], M[SIZE], answer[SIZE]; for (int i = 0; i < SIZE; i++) { answer[i]
unsigned x[SIZE], M[SIZE], answer[SIZE];
for (int i = 0; i < SIZE; i++) {
answer[i] = x[i] % M[i];
}
无符号x[SIZE],M[SIZE],应答[SIZE];
对于(int i=0;i
此外,已知M在1-640000000范围内,如果它有任何帮助的话 如果
M
是编译时常量或循环中的常量,则可以不使用除法。我们可以写作
x/M = (x*(2^n/M))>>n
系数2^n/M
(aka)应在循环之前或编译时计算
例如,如果我们想要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 32768
int x[N],y[N],z[N];
内部主(空){
对于(int i=0;in;
如果(y[i]!=z[i])printf(“%d%d\n”,y[i],z[i]);
}
}
有几种不同的方法来确定幻数和n
。我使用。它可以为您使用SSE2或AVX2来确定32位数字(而不是上面代码中的15位数字)。如果您想看到汇编代码来确定幻数,his也可以为SSE2(可能还有AVX2)确定幻数
有关更多详细信息,请参阅VCL手册第22页。手册中也对其汇编库进行了描述。没有比这快多少。此外,您可能需要检查是否存在一个舍入错误。如果分数部分非常接近
0.5
。除非M是2的幂,否则我认为你运气不好。M
是编译时常数吗?好的,我现在明白了,M每次迭代都会改变M[I]
。我的答案中的方法对你没有帮助。很抱歉,我忘了告诉你m只在运行时可用。我会更新这个问题。谢谢你的回答,我不知道Fog的VCL,它看起来非常有用。@Ricbitm
不需要是编译时常量。它只需要在循环中保持常量。这需要时间计算fact
和n
。如果每次迭代都要这样做,那会比除法慢。但是如果你在循环之前计算它们,那么使用乘法和移位会快得多。事实证明,即使不使用sse,用两次乘法替换mod也确实有好处。再次感谢你的帮助想法。应该指出的是,对于16位数字,有\u mm\u mulhi\u epu16
来获得每个产品的高半部(bit[31:16]
)。这意味着您不必扩展到32位,事实上不应该,因为SSE4pmulld
在Haswell和更高版本上更慢。