我试图在我的代码中使用一些AVX内在函数,并遇到了对数内在函数的砖墙.
使用适用于Linux的英特尔intrinsics指南v3.0.1,我看到内在_mm256_log_ps(__m256)列为"immintrin.h"的一部分,并且在我当前的arch上也受支持.
但是,尝试编译这个简单的测试用例失败,并显示"错误:'_ mm256_log_ps'未在此范围内声明"
这个例子是用编译的 g++-4.8 -march=native -mavx test.cpp
#include <immintrin.h>
int main()
{
__m256 i;
_mm256_log_ps(i);
}
Run Code Online (Sandbox Code Playgroud)
我错过了一些基本的东西吗?某些内在函数是否不受g ++支持且仅在icc中可用?
已解决:此指令不是真正的内在指令,而是作为ICC的英特尔SVML的一部分实现的.
我正在寻找计算高度并行化的trig函数(在1024的块中),并且我想利用至少一些现代架构所具有的并行性.
当我编译一个块
for(int i=0; i<SIZE; i++) {
arr[i]=sin((float)i/1024);
}
Run Code Online (Sandbox Code Playgroud)
海湾合作委员会不会对其进行矢量化,并表示
not vectorized: relevant stmt not supported: D.3068_39 = __builtin_sinf (D.3069_38);
Run Code Online (Sandbox Code Playgroud)
这对我来说很有意义.但是,我想知道是否有一个库可以进行并行三角计算.
只有一个简单的泰勒系列上升到第11阶,GCC将向所有循环进行矢量化,并且我的速度超过了一个天真的sin循环的速度的两倍(具有精确答案,或者具有9阶系列,只有一个位)关闭1600个值的最后两个,加速> 3倍).我确定有人之前遇到过这样的问题,但是当我谷歌时,我发现没有提及任何库等.
A.是否已存在某些内容?
B.如果没有,建议优化并行触发功能?
编辑:我发现所谓的"SLEEF"以下库:http://shibatch.sourceforge.net/ 其描述此文件,并使用SIMD指令来计算几个基本功能.它使用SSE和AVX特定代码,但我认为将其转换为标准C循环并不困难.
__m256d _mm256_log2_pd (__m256d a)除了英特尔之外,SVML 还没有其他编译器可用,他们表示其性能在AMD处理器上是有缺陷的.在g ++ - 4.8中缺少AVX日志内在函数(_mm256_log_ps)中的一些互联网实现?和SSE和AVX的SIMD数学库,但它们似乎比AVX2更多的SSE.还有Agner Fog的矢量库,但是它是一个包含更多东西的大型库,它只是向量log2,所以从它的实现中很难找出向量log2操作的基本部分.
那么有人可以解释如何有效地实现log2()4个double数字向量的操作吗?即就是__m256d _mm256_log2_pd (__m256d a)这样,但可用于其他编译器,并且AMD和Intel处理器的效率相当高.
编辑:在我目前的特定情况下,数字是介于0和1之间的概率,而对数用于熵计算:所有i的和的否定P[i]*log(P[i]).浮点指数的P[i]范围很大,因此数字可以接近0.我不确定准确度,因此会考虑以30位尾数开头的任何解决方案,尤其是可调整的解决方案.
EDIT2:这是我到目前为止的实现,基于https://en.wikipedia.org/wiki/Logarithm#Power_series的 "更有效的系列" .怎么改进?(需要提高性能和精度)
namespace {
const __m256i gDoubleExpMask = _mm256_set1_epi64x(0x7ffULL << 52);
const __m256i gDoubleExp0 = _mm256_set1_epi64x(1023ULL << 52);
const __m256i gTo32bitExp = _mm256_set_epi32(0, 0, 0, 0, 6, 4, 2, 0);
const __m128i gExpNormalizer = _mm_set1_epi32(1023);
//TODO: some 128-bit variable or two 64-bit variables …Run Code Online (Sandbox Code Playgroud) 我必须多次将 10 提高到两倍的幂。
有没有比使用数学库更有效的方法来做到这一点pow(10,double)?如果重要的话,我的双打总是在 -5 到 -11 之间为负。
我假设 pow(double,double) 使用比 pow(10,double) 所需的更通用的算法,因此可能不是最快的方法。鉴于下面的一些答案,这可能是一个不正确的假设。
至于为什么,是对数插值。我有一个 x 和 y 值表。我的对象有一个已知的 x 值(几乎总是双精度值)。
double Dbeta(struct Data *diffusion, double per){
double frac;
while(per>diffusion->x[i]){
i++;
}
frac = (per-diffusion->x[i-1])/(diffusion->x[i]-diffusion->x[i-1]);
return pow(10,log10DB[i-1] + frac * (log10DB[i]-log10DB[i-1]));
}
Run Code Online (Sandbox Code Playgroud)
这个函数被调用了很多次。我被告知要研究分析,所以这就是我首先要做的。
我刚刚被告知我可以使用自然对数代替以 10 为底的,这显然是正确的。(我的愚蠢有时甚至让我自己感到惊讶。)
用自然对数替换所有内容后,一切都运行得更快了。通过分析(这是我今天学到的一个新词),我发现 39% 的代码都用在了 exp 函数中,所以对于那些想知道这部分是否真的阻碍了我的代码的人来说,它是。
c ×2
c++ ×2
algorithm ×1
avx ×1
avx2 ×1
g++ ×1
gcc ×1
intrinsics ×1
logarithm ×1
performance ×1
pow ×1
trigonometry ×1