7

我需要一个 AVX512double pow(double, int n)函数(我需要它来进行准确的二项分布计算)。特别是我希望拥有 AVX512ER 的 Knights Landing。一种方法是

x^n = exp2(log2(x)*n)

Knights Corner 有vlog2ps指令 ( _mm512_log2_psintrinsic) 和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;
}

是否有比重复平方更有效的算法来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;
}

指数是 int32 而不是 int64。理想情况下,我会使用__m256i八个整数。但是,这需要 AVX512VL 将 512b 操作扩展到 256b 和 128b,但 KNL 没有 AVX512VL。相反,我对 32 位整数使用 512b 操作,并将 16b 掩码转换为 8b。

4

0 回答 0