计算复杂数组的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++。< P>给定所有循环迭代都是独立的,可以使用以下代码进行并行化:计算复杂数组的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
#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.
}