检查AVX内在__m256
(8 float
的向量)是否包含任何inf
的最佳方法是什么?我试过了
__m256 X=_mm256_set1_ps(1.0f/0.0f);
_mm256_cmp_ps(X,X,_CMP_EQ_OQ);
但与true
相比。请注意,此方法会找到nan
(与false
比较)。因此,一种方法是检查X!=nan && 0*X==nan
:
__m256 Y=_mm256_mul_ps(X,_mm256_setzero_ps()); // 0*X=nan if X=inf
_mm256_andnot_ps(_mm256_cmp_ps(Y,Y,_CMP_EQ_OQ),
_mm256_cmp_ps(X,X,_CMP_EQ_OQ));
然而,这似乎有些冗长。有更快的方法吗?
答案 0 :(得分:5)
如果你想检查一个载体是否有任何无穷大:
#include <limits>
bool has_infinity(__m256 x){
const __m256 SIGN_MASK = _mm256_set1_ps(-0.0);
const __m256 INF = _mm256_set1_ps(std::numeric_limits<float>::infinity());
x = _mm256_andnot_ps(SIGN_MASK, x);
x = _mm256_cmp_ps(x, INF, _CMP_EQ_OQ);
return _mm256_movemask_ps(x) != 0;
}
如果您想要无穷大值的矢量蒙版:
#include <limits>
__m256 is_infinity(__m256 x){
const __m256 SIGN_MASK = _mm256_set1_ps(-0.0);
const __m256 INF = _mm256_set1_ps(std::numeric_limits<float>::infinity());
x = _mm256_andnot_ps(SIGN_MASK, x);
x = _mm256_cmp_ps(x, INF, _CMP_EQ_OQ);
return x;
}
答案 1 :(得分:2)
我认为更好的解决方案是使用vptest
而不是vmovmskps
。
bool has_infinity(const __m256 &x) {
__m256 s = _mm256_andnot_ps(_mm256_set1_ps(-0.0), x);
__m256 cmp = _mm256_cmp_ps(s,_mm256_set1_ps(1.0f/0.0f),0);
__m256i cmpi = _mm256_castps_si256(cmp);
return !_mm256_testz_si256(cmpi,cmpi);
}
内在_mm256_castps_si256
只是为了让编译器开心"This intrinsic is only used for compilation and does not generate any instructions, thus it has zero latency."
vptest
优于vmovmskps
,因为它设置了零标记而vmovmskps
没有。对于vmovmskps
,编译器必须生成test
以设置零标志。
答案 2 :(得分:1)
我有一个想法,但如果你想测试所有元素是无限的,它最终只会有所帮助。糟糕。
使用AVX2,您可以使用PTEST
测试所有无限元素。我有这个想法使用xor来比较EOF对this question的评论中的相等性,我在那里用我的答案。我以为我能够制作一个测试换任何inf的较短版本,但当然pxor
只能作为所有256b相等的测试。
#include <limits>
bool all_infinity(__m256 x){
const __m256i SIGN_MASK = _mm256_set1_epi32(0x7FFFFFFF); // -0.0f inverted
const __m256 INF = _mm256_set1_ps(std::numeric_limits<float>::infinity());
x = _mm256_xor_si256(x, INF); // other than sign bit, x will be all-zero only if all the bits match.
return _mm256_testz_si256(x, SIGN_MASK); // flags are ready to branch on directly
}
使用AVX512,有一个__mmask8 _mm512_fpclass_pd_mask (__m512d a, int imm8)
。 (vfpclasspd
)。 (见Intel's guide)。它的输出是一个掩码寄存器,我没有考虑对那里的值进行测试/分支。但你可以测试+/-零,+ / - inf,Q / S NaN,Denormal,Negative中的任何一个/全部。