__m128i初始化与_mm_madd_epi16运算结果异常,求解释
问题原因分析
你的结果不符合预期,核心是两个错误:初始化方式错误,以及对_mm_madd_epi16的操作逻辑理解偏差。
1. __m128i初始化方式的问题
__m128i是128位向量类型,直接用{1,2,3,4,5,6,7,8}这种整数列表初始化时,编译器不会按你预期的8个16位整数填充向量。实际编译器会将列表中的每个整数当作字节(8位)填充到向量的内存中,剩余字节补0。
以你的x为例,内存布局(小端模式下)是:
字节0:0x01, 字节1:0x02, 字节2:0x03, 字节3:0x04, 字节4:0x05, 字节5:0x06, 字节6:0x07, 字节7:0x08, 字节8-15:0x00
当作为8个16位整数看待时,每个16位元素由相邻两个字节组成(小端模式下低字节在前),所以x的16位元素实际是:[0x0201(513), 0x0403(1027), 0x0605(1541), 0x0807(2055), 0, 0, 0, 0]
同理,y的16位元素实际是:[0x140A(5130), 0x281E(10270), 0x3C32(15410), 0x5046(20550), 0, 0, 0, 0]
2. _mm_madd_epi16的操作逻辑
_mm_madd_epi16是有符号16位乘加压缩指令,它的操作规则是:
将两个输入向量的相邻两对16位元素分别相乘,再将乘积相加,得到一个32位结果。最终输出向量包含4个32位整数(共128位)。
对应你的实际输入:
- 第一个32位结果 = 5135130 + 102710270 = 2631690 + 10547290 = 13178980
这个值按16位拆分(小端模式)就是低16位0x1864(6244),高16位0x00C9(201),正好是你看到的前两个元素。 - 后续结果也是基于错误的16位元素计算而来,自然和预期不符。
正确的写法
要实现你预期的1*10 +2*20=50这类计算,需要正确初始化16位元素的向量:
// 方法1:使用_mm_set_epi16(注意参数顺序是从高到低的16位元素) __m128i x = _mm_set_epi16(8,7,6,5,4,3,2,1); __m128i y = _mm_set_epi16(80,70,60,50,40,30,20,10); // 方法2:用16位数组加载 int16_t x_arr[] = {1,2,3,4,5,6,7,8}; int16_t y_arr[] = {10,20,30,40,50,60,70,80}; __m128i x = _mm_loadu_si128((__m128i*)x_arr); __m128i y = _mm_loadu_si128((__m128i*)y_arr); __m128i z = _mm_madd_epi16(x, y);
此时z的第一个32位元素就是1*10 +2*20=50,符合你的预期。
内容的提问来源于stack exchange,提问作者Zvi Vered
相关产品推荐
相关产品推荐

