我有以下瓶颈功能。
typedef unsigned char byte;
void CompareArrays(const byte * p1Start, const byte * p1End, const byte * p2, byte * p3)
{
const byte b1 = 128-30;
const byte b2 = 128+30;
for (const byte * p1 = p1Start; p1 != p1End; ++p1, ++p2, ++p3) {
*p3 = (*p1 < *p2 ) ? b1 : b2;
}
}
我想用SSE2内部函数替换C++
代码。我尝试了_mm_cmpgt_epi8
,但它使用了签名比较。我需要无符号比较。
是否有任何技巧(SSE,SSE2,SSSE3)来解决我的问题?
注意: 我不想在这种情况下使用多线程。
答案 0 :(得分:9)
而不是抵消已签名的值以使其无符号,更有效的方法是执行以下操作:
_mm_min_epu8
获取p1的无符号最小值,p2 _mm_cmpeq_epi8
_mm_or_si128
和_mm_andc_si128
的掩码来选择合适的b1 / b2值请注意,总共有4条指令,而使用offset + signed比较方法则为5条。
答案 1 :(得分:2)
您可以从数字中减去127,然后使用_mm_cmpgt_epi8
答案 2 :(得分:2)
是的,这可以在SIMD中完成,但制作蒙版需要几个步骤。
Ruslik说得对,我想。您希望使用0x80对每个组件进行xor以翻转有符号和无符号比较的意义。 _mm_xor_si128(PXOR
)可以解决这个问题 - 在将掩码加载到SIMD寄存器之前,您需要在某处创建掩码作为静态char数组。然后_mm_cmpgt_epi8会为您提供一个掩码,您可以使用按位AND(例如_mm_and_si128
)来执行屏蔽移动。
答案 3 :(得分:1)
是的,SSE不会在这里工作。 您可以使用OpenMP:
在多核计算机上提高此代码性能void CompareArrays(const byte * p1Start, const byte * p1End, const byte * p2, byte * p3) { const byte b1 = 128-30; const byte b2 = 128+30; int n = p1End - p1Start; #pragma omp parallel for for (int i = 0; i < n; ++p1, ++i) { p3[i] = (p1[i] < p2[i]) ? b1 : b2; } }
答案 4 :(得分:-1)
不幸的是,上面的许多答案都是不正确的。我们假设一个3位字:
无符号:4 5 6 7 0 1 2 3 ==签名:-4 -3 -2 -1 0 1 2 3(位:100 101 110 111 000 001 010 011)
Paul R的方法不正确。假设我们想知道3&gt; 2. min(3,2)== 2,这表示是,所以这个方法适用于此。现在假设我们想知道是否7> 2.签名表示中的值7为-1,因此min(-1,2)== -1,这表示7不大于2无符号。
安德烈的方法也不正确。假设我们想知道7&gt; 2,或a = 7,b = 2.符号表示中的值7为-1,因此第一项(a> b)失败,并且该方法表明7不大于2.
然而,由Alexey纠正的BJobnh的方法是正确的。只需从值中减去2 ^(n-1),其中n是位数。在这种情况下,我们将减去4以获得新的相应值:
旧签名:-4 -3 -2 -1 0 1 2 3 =&gt; new signed:0 1 2 3 -4 -3 -2 -1 == new unsigned 0 1 2 3 4 5 6 7。
换句话说,unsigned_greater_than(a,b)等同于signed_greater_than(a - 2 ^(n-1),b - 2 ^(n-1))。
答案 5 :(得分:-3)
使用pcmpeqb并成为你的力量。