计算复杂数组的abs()值的最快方法 我想计算C或C++中复杂数组元素的绝对值。最简单的方法是 for(int i = 0; i < N; i++) { b[i] = cabs(a[i]); } for(int i=0;i给定所有循环迭代都是独立的,可以使用以下代码进行并行化: #pragma omp parallel for for(int i = 0; i < N; i++) { b[i] = cabs(a[i]); } #pragma omp parallel for 对于(int i=0;i

计算复杂数组的abs()值的最快方法 我想计算C或C++中复杂数组元素的绝对值。最简单的方法是 for(int i = 0; i < N; i++) { b[i] = cabs(a[i]); } for(int i=0;i给定所有循环迭代都是独立的,可以使用以下代码进行并行化: #pragma omp parallel for for(int i = 0; i < N; i++) { b[i] = cabs(a[i]); } #pragma omp parallel for 对于(int i=0;i,c++,c,arrays,complex-numbers,C++,C,Arrays,Complex Numbers,但对于大的向量,这将是缓慢的。有没有办法加快速度(例如,通过使用并行化)?语言可以是C或C++。< P>给定所有循环迭代都是独立的,可以使用以下代码进行并行化: #pragma omp parallel for for(int i = 0; i < N; i++) { b[i] = cabs(a[i]); } #pragma omp parallel for 对于(int i=0;i

但对于大的向量,这将是缓慢的。有没有办法加快速度(例如,通过使用并行化)?语言可以是C或C++。

< P>给定所有循环迭代都是独立的,可以使用以下代码进行并行化:

#pragma omp parallel for
for(int i = 0; i < N; i++)
{
    b[i] = cabs(a[i]);
}
#pragma omp parallel for
对于(int i=0;i
当然,要使用它,您应该在编译代码时启用OpenMP支持(通常通过使用/OpenMP标志或设置项目选项)。

您可以在中找到几个OpenMP使用示例。

或使用Concurrency::Parallel\u进行类似操作:

Concurrency::parallel_for(0, N, [&a, &b](int i)
{
b[i] = cabs(a[i]);
});

另外,您可以使用std::future和std::async(它们是C++11的一部分),也许这是实现您想要做的事情的更明确的方法:

#include <future>

...

int main()
{
    ...

    // Create async calculations
    std::future<void> *futures = new std::future<void>[N];
    for (int i = 0; i < N; ++i)
    {
        futures[i] = std::async([&a, &b, i]
        {
            b[i] = std::sqrt(a[i]);
        });
    }
    // Wait for calculation of all async procedures
    for (int i = 0; i < N; ++i)
    {
        futures[i].get();
    }

    ...

    return 0;
}
#包括
...
int main()
{
...
//创建异步计算
标准::未来*未来=新标准::未来[N];
对于(int i=0;i

我们首先创建异步过程,然后等待一切计算完成。
这里我用sqrt代替出租车,因为我不知道什么是出租车。我相信这没关系。
此外,您可能会发现此链接很有用:

使用向量运算

如果您有glibc 2.22(相当新的版本),则可以使用OpenMP 4.0的SIMD功能来实现

Libmvec是glibc2.22中添加的向量数学库

添加矢量数学库以支持OpenMP4.0的SIMD结构 (2.8 in)加入— 向量数学函数的向量实现

向量数学函数是相应标量数学的向量变体 使用SIMD ISA扩展(如SSE或AVX)实施的操作 x86_64)。它们接受压缩向量参数,对 压缩向量参数的每个元素,并返回压缩向量 结果。使用向量数学函数比重复调用要快 标量数学例程

另外,请参见

如果您在Solaris上运行,则可以显式使用对复数向量进行运算,以获得每个向量的绝对值:

说明

这些函数计算整个向量的函数hypot(x,y) 价值观的同时


libmvec
的源代码可以在上找到,而
vhypot()
代码特别是在上我不记得Sun Microsystems是否提供过Linux版本的
libmvec。因此
与否。

如果您使用的是现代编译器(例如GCC 5),您可以使用,这将为您提供一个很好的数组表示法,自动使用和并行化

因此,如果要并行运行它们,您可以执行以下操作:

#include <cilk/cilk.h>

cilk_for(int i = 0; i < N; i++)
{
    b[i] = cabs(a[i]);
}
在这种情况下,编译器和运行时环境将决定它应该被SIMD到哪个级别以及应该并行化什么(最佳方法是并行地将SIMD应用于大型ish块)。 由于这是由工作调度器在运行时决定的,Intel声称它能够提供接近最优的调度,并且应该能够最佳地利用缓存。

使用
\pragma simd
(即使使用
-Ofast
)或者依赖于编译器的自动矢量化,这是一个更好的例子,说明了为什么盲目地期望编译器高效地实现SIMD是一个坏主意。为了有效地使用SIMD,您需要使用数组结构数组。例如,对于SIMD宽度为4的单浮点,可以使用

//struct of arrays of four complex numbers
struct c4 {
    float x[4];  // real values of four complex numbers 
    float y[4];  // imaginary values of four complex numbers
};
下面的代码显示了如何使用SSE为x86指令集执行此操作

#include <stdio.h>
#include <x86intrin.h>
#define N 10

struct c4{
    float x[4];
    float y[4];
};

static inline void cabs_soa4(struct c4 *a, float *b) {
    __m128 x4 = _mm_loadu_ps(a->x);
    __m128 y4 = _mm_loadu_ps(a->y);
    __m128 b4 = _mm_sqrt_ps(_mm_add_ps(_mm_mul_ps(x4,x4), _mm_mul_ps(y4,y4)));
    _mm_storeu_ps(b, b4);
}  

int main(void)
{
    int n4 = ((N+3)&-4)/4;  //choose next multiple of 4 and divide by 4
    printf("%d\n", n4);
    struct c4  a[n4];  //array of struct of arrays
    for(int i=0; i<n4; i++) {
        for(int j=0; j<4; j++) { a[i].x[j] = 1, a[i].y[j] = -1;}
    }
    float b[4*n4];
    for(int i=0; i<n4; i++) {
        cabs_soa4(&a[i], &b[4*i]);
    }
    for(int i = 0; i<N; i++) printf("%.2f ", b[i]); puts("");
}

我没有在这里实现数组的struct of array,但是调整代码应该很容易。

你可以看看,它优化了缓存使用的操作。并行化或将计算卸载到GPU可能会有所帮助,这取决于输入的大小。手动SIMD实现也可能如此,特别是如果快速近似平方根可能就足够了。另外,您是否确定您确实需要平方根,并且您下一次的计算可能不会满足于直接使用平方和,例如用于比较大小?您可能想看看。@doynax:我需要确切的值,这就是问题所在。@arc_Lupse:恐怕复杂的绝对计算本质上是不精确的。也许你可以寻找一个极坐标表示法,或者以某种方式象征性地评估你的计算。您确定不能满足于IEEE-754双精度浮点算法提供的15位奇数精度吗?
cabs
是C的C99标准中定义的复杂的
abs
。此外:与其他方法相比,sqrt不是很慢吗?此外,您可以使用OpenMP的SIMD选项,请参阅。我在另一个答案中对此进行了扩展。两个问题:如果在上一个示例中数组是malloc'ed的,编译器如何知道数组的大小?我如何启用#pragma?@arc#lup?并行性最终由运行时调度器决定。最佳调度不仅取决于阵列的大小,还取决于
cabs
功能的速度(在这种情况下非常快,在您希望单独并行的情况下,可能非常慢)。@arc_lube
#include
感谢分块的想法,但是我需要整个阵列来处理它(应用fft),因此我不可能这样做。
//struct of arrays of four complex numbers
struct c4 {
    float x[4];  // real values of four complex numbers 
    float y[4];  // imaginary values of four complex numbers
};
#include <stdio.h>
#include <x86intrin.h>
#define N 10

struct c4{
    float x[4];
    float y[4];
};

static inline void cabs_soa4(struct c4 *a, float *b) {
    __m128 x4 = _mm_loadu_ps(a->x);
    __m128 y4 = _mm_loadu_ps(a->y);
    __m128 b4 = _mm_sqrt_ps(_mm_add_ps(_mm_mul_ps(x4,x4), _mm_mul_ps(y4,y4)));
    _mm_storeu_ps(b, b4);
}  

int main(void)
{
    int n4 = ((N+3)&-4)/4;  //choose next multiple of 4 and divide by 4
    printf("%d\n", n4);
    struct c4  a[n4];  //array of struct of arrays
    for(int i=0; i<n4; i++) {
        for(int j=0; j<4; j++) { a[i].x[j] = 1, a[i].y[j] = -1;}
    }
    float b[4*n4];
    for(int i=0; i<n4; i++) {
        cabs_soa4(&a[i], &b[4*i]);
    }
    for(int i = 0; i<N; i++) printf("%.2f ", b[i]); puts("");
}
for(int i = 0; i < nchunks; i++) {
    for(int j = 0; j < chunk_size; j++) {
        b[i*chunk_size+j] = cabs(a[i*chunk_size+j]);
    }
    foo(&b[i*chunck_size]); // foo is computationally intensive.
}