使用AVX与NaN比较

我正在尝试使用英特尔的AVX内在函数为BPSK创建一个快速解码器。 我有一组复数表示为交错浮点数,但由于BPSK调制,只需要实部(或偶数索引浮点数)。 当x < 0时,每个浮点x映射到0 ,如果x >= 0 ,则映射到1 。 这是使用以下例程完成的:

 static inline void normalize_bpsk_constellation_points(int32_t *out, const complex_t *in, size_t num) { static const __m256 _min_mask = _mm256_set1_ps(-1.0); static const __m256 _max_mask = _mm256_set1_ps(1.0); static const __m256 _mul_mask = _mm256_set1_ps(0.5); __m256 res; __m256i int_res; size_t i; gr_complex temp; float real; for(i = 0; i 0, 1->1 */ res = _mm256_add_ps(res, _max_mask); res = _mm256_mul_ps(res, _mul_mask); /* And then round to the nearest integer */ res = _mm256_round_ps(res, _MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC); int_res = _mm256_cvtps_epi32(res); _mm256_store_si256((__m256i *) &out[2*i], int_res); } } 

首先,我将所有收到的浮点数夹在[-1, 1]范围内。 然后经过一些适当的缩放后,结果四舍五入到最接近的整数。 这将映射所有浮点数高于0.51以及所有浮点数低于0.50

如果输入浮点数是正常数字,则该过程正常。 但是,由于前一阶段的某些情况,某些输入浮点数可能是NaN-NaN 。 在这种情况下,’NaN’数字通过_mm256_max_ps()_mm256_min_ps()和所有其他AVX函数传播,导致整数映射-2147483648 ,这当然会导致程序因索引无效而崩溃。

是否有任何解决方法可以避免此问题,或者至少使用AVXNaN设置为0

你可以用简单的方式开始,比较和掩盖:(未测试)

 res = _mm256_cmp_ps(res, _mm256_setzero_ps(), _CMP_NLT_US); ires = _mm256_srl_epi32(_mm256_castps_si256(res), 31); 

或者转移和xor :(也没有经过测试)

 ires = _mm256_srl_epi32(_mm256_castps_si256(res), 31); ires = _mm256_xor_epi32(ires, _mm256_set1_epi32(1)); 

这个版本也将关注NaN的标志(并忽略NaN-ness)。

没有AVX2的替代品(未经测试)

 res = _mm256_cmp_ps(res, _mm256_setzero_ps(), _CMP_NLT_US); res = _mm256_and_ps(res, _mm256_set1_ps(1.0f)); ires = _mm256_cvtps_epi32(res); 

Harold为你真正提出的问题找到了一个很好的解决方案,但我想明确一点,在钳位时消除NaN值非常简单。 如果任一参数是NaN,MINPS和MAXPS只返回第二个参数。 所以你需要做的就是交换参数顺序,NaN也会被钳制。 例如,以下将NaNs钳制为_min_mask:

 res = _mm256_max_ps(_mm256_min_ps(_max_mask, res), _min_mask);