在double / simd中构建2 ^ n

时间:2013-11-12 20:13:16

标签: assembly simd

我正在尝试使用双重表示来构建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加倍,在舍入函数之后我将得到一个寄存器sse2 __m128d v =(4.0,3.0);形成这个寄存器如何计算2 ^ v ...我被阻塞主要是由于将__m128d转换为__m128i,它不存在(它仍然存在一个强制转换,但它不会移位,只需更改寄存器的“解释”) / INT)。

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

所以帮助^ _ ^'

最佳,

1 个答案:

答案 0 :(得分: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只编译2个insn,as you can see on the Godbolt Compiler Explorer

输出是:

v = 4.000000 16.000000 512.000000 128.000000

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

如果您使用double的向量,与OP一样,则使用_mm256_cvtpd_epi32_mm256_cvtepu32_epi64。 (双 - &gt; int64直到AVX-512才能直接使用。)