2

我正在尝试使用双重表示来构建 2^n 。诀窍是(众所周知)

// tips to calculate 2^n using the exponent of the double IEEE representation
union ieee754{
    double d;
    uint32_t i[2];
};

// Converts an unsigned long long to a double
inline double uint642dp(uint64_t ll) {
  ieee754 tmp;
  tmp.ll=ll;
  return tmp.d;
}
-----------------------------------
// e^x = 2^n e^y, n = round(x/log(2)+0.5)

double x = 4.3; // start from there
double y = round(x/log(2)+0.5)
int n = (int)y; // convert in to double 
uint642dp(( ((uint64_t)n) +1023)<<52); // calculate 2^n fastly

如果 n = 4,它将返回 16。

目前我正在寻找相同的这个,但用于 SIMD 计算。考虑到 SSE2 double,在轮函数之后我会得到一个寄存器 sse2 __m128d v = (4.0, 3.0); 形成这个寄存器如何计算 2^v ...我被阻塞主要是由于将 __m128d 转换为 __m128i,它不存在(它仍然存在一个强制转换但它不移动位,只需更改寄存器双精度的“解释” /int)。

我不想将数据从 simd 寄存器返回到普通寄存器来进行转换。它肯定存在 SIMD 的提示,但我不知道。

所以帮助^_^'

最好的,

4

1 回答 1

2

您正在寻找的技巧_mm256_castsi256_pd实际上是内在的,它允许您将整数的 SIMD 数组转换为双精度的 SIMD 数组。这仅用于 C/C++ 类型检查,不会转换为任何指令。

这是执行此操作的代码片段(仅在某些指数范围内有效):

#include <immintrin.h>

__m256d pow2n (__m256i n)
{
    const __m256i bias = _mm256_set1_epi64x( 1023 );
    __m256i t = _mm256_add_epi64 (n, bias);
    t = _mm256_slli_epi64 (t, 52);
    return _mm256_castsi256_pd (t) ;
}

#include <cstdio>

int main ()
{
        __m256i rn = _mm256_set_epi64x( 7, 9, 4, 2 );
        __m256d pn = pow2n (rn) ;
        double v [4] ;
        _mm256_storeu_pd (v, pn) ;
        printf ("v = %lf %lf %lf %lf\n", v[0], v[1], v[2], v[3]) ;
        return 0 ;
}

pow2n如您在 Godbolt Compiler Explorer 上所见,仅编译为 2 个 insn

输出是:

v = 4.000000 16.000000 512.000000 128.000000

这需要 AVX2,但 128 位版本只需要 SSE2。请注意,指数以 64 位整数的形式提供。如果您有 32 位整数,请使用_mm256_cvtepu32_epi64.

如果您从 的向量开始double,例如 OP,则使用_mm256_cvtpd_epi32and _mm256_cvtepu32_epi64。(在 AVX-512 之前,double -> int64 直接不可用)。

于 2016-05-01T15:37:00.247 回答