You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

半字节解包为字节:保留符号的高效实现方法问询

解决方案:符号扩展半字节到字节(SSE/AVX)

针对你的需求——将4位有符号半字节补码符号扩展为8位,以下是不同指令集下的高效实现方式:

1. AVX2 环境(推荐,指令最少)

AVX2 提供了直接操作8位元素的算术右移指令 _mm_srai_epi8,可以一步完成符号扩展:

const __m128i mask = _mm_set1_epi8(0x0F);
// 提取低4位半字节并符号扩展
__m128i vec_unpack_one = _mm_and_si128(vec, mask);
vec_unpack_one = _mm_slli_epi8(vec_unpack_one, 4);  // 将4位符号位移到8位元素的最高位
vec_unpack_one = _mm_srai_epi8(vec_unpack_one, 4);  // 算术右移,符号扩展高4位

// 提取高4位半字节并符号扩展
__m128i vec_unpack_two = _mm_and_si128(_mm_srli_epi16(vec, 4), mask);
vec_unpack_two = _mm_slli_epi8(vec_unpack_two, 4);
vec_unpack_two = _mm_srai_epi8(vec_unpack_two, 4);

原理:

  • 先将4位半字节左移4位,让原半字节的符号位(第3位)成为8位元素的最高位(第7位)
  • 算术右移4位时,CPU会用符号位填充高4位,自动完成补码的符号扩展。比如原半字节0x0B(1011,-5)左移后变为0xB0(10110000),算术右移4位后得到0xFB(11111011,-5),完全符合需求。

2. SSE2 环境(兼容旧CPU)

SSE2 没有8位算术右移指令,可通过16位算术右移模拟,或用掩码加法实现:

方法一:16位算术右移模拟

const __m128i mask = _mm_set1_epi8(0x0F);
// 处理低4位半字节
__m128i vec_unpack_one = _mm_and_si128(vec, mask);
vec_unpack_one = _mm_unpacklo_epi8(vec_unpack_one, _mm_setzero_si128());  // 8位转16位
vec_unpack_one = _mm_slli_epi16(vec_unpack_one, 12);  // 符号位移到16位元素最高位
vec_unpack_one = _mm_srai_epi16(vec_unpack_one, 12);  // 16位算术右移完成符号扩展
vec_unpack_one = _mm_packepi16(vec_unpack_one, vec_unpack_one);  // 16位转回8位

// 处理高4位半字节
__m128i vec_unpack_two = _mm_and_si128(_mm_srli_epi16(vec, 4), mask);
vec_unpack_two = _mm_unpacklo_epi8(vec_unpack_two, _mm_setzero_si128());
vec_unpack_two = _mm_slli_epi16(vec_unpack_two, 12);
vec_unpack_two = _mm_srai_epi16(vec_unpack_two, 12);
vec_unpack_two = _mm_packepi16(vec_unpack_two, vec_unpack_two);

方法二:掩码加法实现

const __m128i mask = _mm_set1_epi8(0x0F);
const __m128i sign_bit = _mm_set1_epi8(0x08);
const __m128i extend_mask = _mm_set1_epi8(0xF0);

// 处理低4位半字节
__m128i vec_unpack_one = _mm_and_si128(vec, mask);
__m128i is_negative = _mm_cmpeq_epi8(_mm_and_si128(vec_unpack_one, sign_bit), sign_bit);
vec_unpack_one = _mm_or_si128(vec_unpack_one, _mm_and_si128(is_negative, extend_mask));

// 处理高4位半字节
__m128i vec_unpack_two = _mm_and_si128(_mm_srli_epi16(vec, 4), mask);
is_negative = _mm_cmpeq_epi8(_mm_and_si128(vec_unpack_two, sign_bit), sign_bit);
vec_unpack_two = _mm_or_si128(vec_unpack_two, _mm_and_si128(is_negative, extend_mask));

原理:

  • 通过_mm_cmpeq_epi8判断半字节的符号位是否为1,生成全1的掩码字节
  • 将掩码与0xF0相与,得到符号扩展所需的高4位填充值,再与原半字节按位或完成扩展。

内容的提问来源于stack exchange,提问作者Srihari S

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 22:14:56