如何根据另一个包含 0 或 1 个元素的向量有条件地否定 AVX2 int16_t 向量?

How conditionally negate an AVX2 int16_t vector based on another vector of 0 or 1 elements?

我有一个向量 int16_t beta = {1,1,0,0,0,0,0,0}

我想用 AVX2 实现这个等式

c[i] = a[i] + (-1)^beta[i] * b[i]

其中 a、b、c 和 beta 都是 int16_t 的 AVX2 向量。


我想通了,如果我可以将 1 映射到 -32768,就可以避免乘法运算。我的意思是,可以使用 simd 内在函数的 OR 和 NEGATE 函数来翻转向量 b 的符号。

我知道 1 可以使用左移操作映射到 -32768,但是 avx2 没有任何位移操作1。有什么方法可以使用 simd 有效地将 1 映射到 -32768?


编者脚注1:_mm256_slli_epi16(x, 15)确实存在。但是还有其他方法可以实现整个公式所以这个问题毕竟很有趣。

你可以变换

c[i] = a[i] + (-1)^beta[i] * b[i]

c[i] = a[i] - (beta[i] AND b[i]) + ((NOT beta[i]) AND b[i])

因为原始公式转换为 "subtract this bit if beta[i] is set, otherwise add it"。
(我不知道你打算为 c[i] = 0 + (-1) * 1c[i] = 1 + 1 * 1 发生什么 - 我假设这里是带进位的正常算术加法,与索引符号相反)。
所以你可以删除索引:

c = a - (beta & b) + (!beta & b)

我不知道这是否与 AVX2 内在函数有很好的映射,但我怀疑它确实如此。

有条件否定的快速方法,使用 _mm256_sign_epi16。掩码不是正确的形式,但可以通过向每个元素添加 0x7FFF 将其转换为正确的形式,因此:

__m256i masks = _mm256_add_epi16(beta, _mm256_set1_epi16(0x7FFF));
__m256i res = _mm256_add_epi16(a, _mm256_sign_epi16(b, masks));