Z b*_*son 6 x86 pow xeon-phi avx512
我需要一个AVX512 double pow(double, int n)功能(我需要它进行二项分布计算,这需要精确).对于拥有AVX512ER的Knights Landing,我特别喜欢这个.获得这个的一种方法是
x^n = exp2(log2(x)*n)
Run Code Online (Sandbox Code Playgroud)
Knights Corner有vlog2ps指令(_mm512_log2_ps内在的)和vexp223ps指令(_mm512_exp223_ps intrinsic),所以至少我可以float pow(float, float)用这两个指令来做.
然而,在Knights Landing中我找不到log2指令.我确实在AVX512ER中找到了一条vexp2pd指令(_mm512_exp2a23_pd内在的).我觉得奇怪的是Knights Corner有一个log2指令但Knights Landing更新更好没有.
现在我已经实现了pow(double, n) 使用重复的平方,但我认为如果我有一个log2指令会更有效率.
//AVX2 but easy to convert to AVX512 with mask registers
static __m256d pown_AVX2(__m256d base, __m256i exp) {
__m256d result = _mm256_set1_pd(1.0);
int mask = _mm256_testz_si256(exp, exp);
__m256i onei = _mm256_set1_epi64x(1);
__m256d onef = _mm256_set1_pd(1.0);
while(!mask) {
__m256i t1 = _mm256_and_si256(exp, onei);
__m256i t2 = _mm256_cmpeq_epi64(t1, _mm256_setzero_si256());
__m256d t3 = _mm256_blendv_pd(base, onef, _mm256_castsi256_pd(t2));
result = _mm256_mul_pd(result, t3);
exp = _mm256_srli_epi64(exp, 1);
base = _mm256_mul_pd(base,base);
mask = _mm256_testz_si256(exp, exp);
}
return result;
}
Run Code Online (Sandbox Code Playgroud)
double pow(double, int n)使用AVX512和AVX512ER比重复平方有更高效的算法吗?有一个简单的方法(例如,有一些指示)来获得log2?
这是使用重复平方的AVX512F版本
static __m512d pown_AVX512(__m512d base, __m512i pexp) {
__m512d result = _mm512_set1_pd(1.0);
__m512i onei = _mm512_set1_epi32(1);
__mmask8 mask;
do {
__m512i t1 = _mm512_and_epi32(pexp, onei);
__mmask8 mask2 = _mm512_cmp_epi32_mask(onei, t1, 0);
result = _mm512_mask_mul_pd(result, mask2, result, base);
pexp = _mm512_srli_epi32(pexp, 1);
base = _mm512_mul_pd(base,base);
mask = _mm512_test_epi32_mask(pexp, pexp);
} while(mask);
return result;
}
Run Code Online (Sandbox Code Playgroud)
指数是int32而不是int64.理想情况下,我会使用__m256i八个整数.但是,这需要AVX512VL,它将512b操作扩展到256b和128b,但KNL没有AVX512VL.相反,我在32位整数上使用512b操作,然后将16b掩码转换为8b.