Mic*_*ael 1 c++ algorithm sse simd avx
我有一个功能:
void Func(const int * a, const int * b, size_t size, int p, int * c)
{
for (size_t i = 0; i < size; ++i)
c[i] = (a[i]*b[i])%p;
}
Run Code Online (Sandbox Code Playgroud)
此函数对整数数组执行许多模乘.所有整数都是正数.我需要提高其性能.
我想到了SSE和AVX.但它们没有向量化乘法的矢量化操作.或许我错了?
也许有人知道解决这个问题的任何可能性吗?
首先,我想指出使用浮点数可以实现模运算:
d % p = d - int(float(d)/float(p))*p.
Run Code Online (Sandbox Code Playgroud)
尽管右侧部分的操作量大于左侧,但这部分是优选的,因为它可以使用SSE/AVX进行矢量化.
SSE4.1用于32x32 => 32位整数乘法的实现.请注意,从FP到整数的转换是用舍入到最接近的; cvttps_epi32如果你想要像C float-> integer conversions这样的语义,请使用截断为零().
void Func(const int * a, const int * b, size_t size, int p, int * c)
{
__m128 _k = _mm_set1_ps(1.0f / p);
__m128i _p = _mm_set1_epi32(p);
for (size_t i = 0; i < size; i += 4)
{
__m128i _a = _mm_loadu_si128((__m128i*)(a + i));
__m128i _b = _mm_loadu_si128((__m128i*)(b + i));
__m128i _d = _mm_mullo_epi32(_a, _b);
__m128i _e = _mm_cvtps_epi32(_mm_mul_ps(_mm_cvtepi32_ps(_d), _k)); // e = int(float(d)/float(p));
__m128i _c = _mm_sub_epi32(_d, _mm_mullo_epi32(_e, _p));
_mm_storeu_si128((__m128i*)(c + i), _c);
}
}
Run Code Online (Sandbox Code Playgroud)
使用AVX的实现:
void Func(const int * a, const int * b, size_t size, int p, int * c)
{
__m256 _k = _mm256_set1_ps(1.0f / p);
__m256i _p = _mm256_set1_epi32(p);
for (size_t i = 0; i < size; i += 8)
{
__m256i _a = _mm256_loadu_si128((__m256i*)(a + i));
__m256i _b = _mm256_loadu_si128((__m256i*)(b + i));
__m256i _d = _mm256_mullo_epi32(_a, _b);
__m256i _e = _mm256_cvtps_epi32(_mm256_mul_ps(_mm256_cvtepi32_ps(_d), _k)); // e = int(float(d)/float(p));
__m256i _c = _mm256_sub_epi32(_d, _mm256_mullo_epi32(_e, _p));
_mm256_storeu_si128((__m256i*)(c + i), _c);
}
}
Run Code Online (Sandbox Code Playgroud)