基于SSE/AVX的条件加法实现:仅非零向量元素相加问询
既然你已经明确知道v_weight里的零元素只会出现在末尾(要么没有,要么最后1、2、3个是0),而且只能用AVX指令集不能碰AVX2,那咱们完全可以利用这个预先的位置信息来做高效的处理,比通用的非零判断要快不少。
核心需求实现:仅在v_weight非零元素位置执行加法
你的需求是:结果向量的每个元素,当v_weight[i]≠0时是v_entropy[i]+v_weight[i],否则保留v_entropy[i]。实现思路很简单:先把v_weight里的零元素位置“过滤掉”(置为0),再和v_entropy相加就好——因为加0不会改变原v_entropy的值。
具体代码如下:
#include <immintrin.h> __m128 add_weighted_entropy(__m128 v_entropy, __m128 v_weight, int zero_count) { __m128 mask; // 根据零元素数量构造掩码:非零位置是全1位(对应浮点数-1.0f),零位置是全0位 switch(zero_count) { case 0: // 没有零元素,掩码全1 mask = _mm_set1_ps(-1.0f); break; case 1: // 最后1个元素是0,前3个位置全1 mask = _mm_castsi128_ps(_mm_setr_epi32(0xffffffff, 0xffffffff, 0xffffffff, 0x00000000)); break; case 2: // 最后2个元素是0,前2个位置全1 mask = _mm_castsi128_ps(_mm_setr_epi32(0xffffffff, 0xffffffff, 0x00000000, 0x00000000)); break; case 3: // 最后3个元素是0,只有第1个位置全1 mask = _mm_castsi128_ps(_mm_setr_epi32(0xffffffff, 0x00000000, 0x00000000, 0x00000000)); break; default: // 按题目描述不会出现这种情况,这里可以加断言或者默认处理 mask = _mm_set1_ps(0.0f); break; } // 过滤v_weight:仅保留非零位置的值,零位置置0 __m128 filtered_weight = _mm_and_ps(v_weight, mask); // 执行加法,得到目标结果 return _mm_add_ps(v_entropy, filtered_weight); }
这里用_mm_castsi128_ps是安全的,因为我们只是把整数向量的位模式当成浮点数向量来用——按位与操作只关心位是0还是1,浮点数的实际值不影响结果。而且直接构造掩码比用_mm_cmpneq_ps生成掩码更高效,省了一条比较指令。
补充需求:将v_entropy对应零元素的位置置零
如果你的场景可以接受零元素位置最终为0(而不是保留原v_entropy的值),那处理起来更直接:用同样的掩码和v_entropy做按位与,就能把对应位置置零,之后再和v_weight相加就行。
代码示例:
#include <immintrin.h> __m128 zero_out_entropy(__m128 v_entropy, int zero_count) { __m128 mask; // 掩码构造逻辑和上面完全一致 switch(zero_count) { case 0: mask = _mm_set1_ps(-1.0f); break; case 1: mask = _mm_castsi128_ps(_mm_setr_epi32(0xffffffff, 0xffffffff, 0xffffffff, 0x00000000)); break; case 2: mask = _mm_castsi128_ps(_mm_setr_epi32(0xffffffff, 0xffffffff, 0x00000000, 0x00000000)); break; case 3: mask = _mm_castsi128_ps(_mm_setr_epi32(0xffffffff, 0x00000000, 0x00000000, 0x00000000)); break; default: mask = _mm_set1_ps(0.0f); break; } // 按位与,将v_entropy中对应零元素的位置置零 return _mm_and_ps(v_entropy, mask); } // 之后相加的话就是: // __m128 zeroed_entropy = zero_out_entropy(v_entropy, zero_count); // __m128 result = _mm_add_ps(zeroed_entropy, v_weight);
这样处理后,零元素位置的结果就是0+0=0,非零位置还是v_entropy[i]+v_weight[i],完全符合你说的“更简便”的需求。
内容的提问来源于stack exchange,提问作者IamIC
相关产品推荐
相关产品推荐

