起初我想指出模操作可以使用浮点数字来实现:
d % p = d - int(float(d)/float(p))*p.
虽然操作的右侧部分的量大然后在左边这部分是可取的,因为它可以使用SSE/AVX进行矢量化。
使用SSE4.1的实现:
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_mul_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_mul_epi32(_e, _p));
_mm_storeu_si128((__m128i*)(c + i), _c);
}
}
使用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_mul_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_mul_epi32(_e, _p));
_mm256_storeu_si128((__m256i*)(c + i), _c);
}
}
这是一个素数。 – Michael
你是否反复使用同一个'p'? “尺寸”通常有多大?如果它足够大或者重复的次数足够多,使用相同的'p',它可能甚至值得JIT编译一个使用硬编码向量移位的循环以及[定点乘法inverse](https://stackoverflow.com/问题/ 41183935 /为什么 - 不 - GCC使用乘法按一个怪号码功能于执行整数-迪维)。或者使用http://libdivide.com/来使用没有JIT的乘法反转,但是会有更多的开销(使用imm8计数的'psrlq'是最好的)。但它可能只有SSE2版本,而不是AVX2或AVX512。 –
'a [i] * b [i]'是否曾经溢出?如果是的话,那会好吗,还是你想要64位结果mod'p'的结果? – chtz