我正在尝试使用双重表示来构建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的提示,但我不知道。
所以帮助^ _ ^'
最佳,
答案 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才能直接使用。)