使用AVX2 Intrinsics实现无符号整数阈值处理的问题
解决AVX2无符号8位整数的阈值比较问题
问题根源
你用的_mm256_cmpgt_epi8是有符号8位整数比较,而diff1是无符号的绝对值差(范围0-255)。当diff1的值在128-255之间时,会被识别为有符号负数,导致diff1 > 15的判断失败——负数不可能大于15,所以这部分值被错误过滤了。
解决方案
无符号8位整数x > 15等价于两种情况的逻辑或:
- 有符号下
x > 15(对应无符号值16-127) - 有符号下
x < 0(对应无符号值128-255,因为无符号128作为有符号数是-128)
我们可以分别生成这两种情况的掩码,再按位或得到最终的无符号大于阈值的掩码,正好贴合你尝试找“小于0的值按位或”的思路。
修改后的代码
__m256i *pIn0, *pIn1,*pOut; __m256i a, b, thres = _mm256_set1_epi8(15); // 阈值设为15 __m256i zero = _mm256_setzero_si256(); // 提前创建零向量,避免循环内重复初始化 for (int i = 0; i < nHeight; i++) { pIn0 = (__m256i*)(pY1 + i * nStepSize); // 无符号8位整数缓冲区1 pIn1 = (__m256i*)(pY2 + i * nStepSize); // 无符号8位整数缓冲区2 pOut = (__m256i*)(pdiffAnd + i * nStepSize); int wLimit = nWidth / 32; for (int j = 0; j < wLimit; j++) { a = _mm256_lddqu_si256(pIn0++); // 加载32个UINT8值 b = _mm256_lddqu_si256(pIn1++); // 加载32个UINT8值 // 计算无符号绝对值差 __m256i diff1 = _mm256_or_si256(_mm256_subs_epu8(a, b), _mm256_subs_epu8(b, a)); // 1. 有符号下diff1 >15的掩码(对应无符号16-127) __m256i diff1Mask = _mm256_cmpgt_epi8(diff1, thres); // 2. 有符号下diff1 <0的掩码(对应无符号128-255) __m256i negMask = _mm256_cmpgt_epi8(zero, diff1); // 3. 合并掩码:无符号>15 = 两种情况的逻辑或 diff1Mask = _mm256_or_si256(diff1Mask, negMask); __m256i blend1 = _mm256_blendv_epi8(diff1, diff1Mask, diff1Mask); _mm256_store_si256(pOut++, blend1); } }
通用替代方案:符号位翻转法
如果以后需要处理任意阈值的无符号比较,更通用的方法是翻转每个字节的符号位(异或0x80),把无符号的大小关系映射为有符号的大小关系,之后直接用_mm256_cmpgt_epi8即可:
// 提前定义符号翻转掩码 __m256i signFlip = _mm256_set1_epi8(0x80); // 翻转diff1和阈值的符号位 __m256i diff1Flipped = _mm256_xor_si256(diff1, signFlip); __m256i thresFlipped = _mm256_xor_si256(thres, signFlip); // 直接用有符号比较,结果等价于无符号diff1 > thres __m256i diff1Mask = _mm256_cmpgt_epi8(diff1Flipped, thresFlipped);
内容的提问来源于stack exchange,提问作者convoluxon
相关产品推荐
相关产品推荐

