并行前缀和-最快的实现 我想用C++实现并行前缀和算法。我的程序应该采用输入数组x[1…N],并且应该在数组y[N]中显示输出。(注意,N的最大值为1000。)
到目前为止,我查阅了许多研究论文,甚至维基百科上的算法。 但我的程序也应该显示输出、步骤以及每个步骤的操作/指令 我想要最快的实现,就像我想要最小化操作数量和步骤一样 例如:并行前缀和-最快的实现 我想用C++实现并行前缀和算法。我的程序应该采用输入数组x[1…N],并且应该在数组y[N]中显示输出。(注意,N的最大值为1000。),c++,algorithm,C++,Algorithm,到目前为止,我查阅了许多研究论文,甚至维基百科上的算法。 但我的程序也应该显示输出、步骤以及每个步骤的操作/指令 我想要最快的实现,就像我想要最小化操作数量和步骤一样 例如: x = {1, 2, 3, 4, 5, 6, 7, 8 } - Input y = ( 1, 3, 6, 10, 15, 21, 28, 36) - Output 但是除了显示y数组作为输出外,我的程序还应该显示每个步骤的操作。我也引用了这个线程,但是可以从中得到很多帮助。下面的代码将完成这项工作 voi
x = {1, 2, 3, 4, 5, 6, 7, 8 } - Input
y = ( 1, 3, 6, 10, 15, 21, 28, 36) - Output
但是除了显示y数组作为输出外,我的程序还应该显示每个步骤的操作。我也引用了这个线程,但是可以从中得到很多帮助。下面的代码将完成这项工作
void prfxSum()
{
int *x=0;
int *y=0;
int sum=0;
int num=0;
int i=0;
cout << "Enter the no. of elements in input array : ";
cin >> num;
x = new int[num];
y = new int[num];
while(i < num)
{
cout << "Enter element " << i+1 << " : ";
cin >> x[i++];
}
cout << "Output array :- " << endl;
i = 0;
while(i < num)
{
sum += x[i];
y[i] = sum;
cout << y[i++] << ", ";
}
delete [] x;
delete [] y;
}
您可以通过从文件中输入1000个数组x[]元素来避免用户输入它。这个问题的答案是:这里:。英伟达文章提供了使用CUDA GPU的最佳可能实现,卡内基梅隆大学PDF文件解释了算法。我还使用MPI实现了一个O(n/p)前缀和,您可以在这里找到: 这是通用算法的伪代码(与平台无关): 例3。高效工作和扫描算法的上扫(减少)阶段(Blelloch 1990之后) 例4。高效工作并行和扫描算法的下扫阶段(Blelloch 1990之后)
其中,x是输入数据,n是输入的大小,d是并行度(CPU数量)。这是一个共享内存计算模型,如果它使用分布式内存您需要向该代码中添加通信步骤,就像我在提供的Github示例中所做的那样。我只实现了数组中所有元素的和(Blelloch的上扫减少部分),而不是使用Aparapi()实现的完整前缀和在java/opencl中。它在上可用,并且是为一般块大小(代码中称为localBatchSize)而不是2编写的。我发现块大小为8最适合我的GPU
虽然实现是有效的(求和计算是正确的),但它的性能比顺序求和差得多。在我的core-i7(8核)CPU上,8388608(8MB)数字的顺序求和大约需要12毫秒,在GPU上并行执行(NVidia Quadro K2000M,384核)大约需要100毫秒。我甚至优化到只传输计算后的最终和,而不是整个数组。如果不进行此优化,则需要20毫秒以上的时间。实现似乎是根据@marcel valdez orozco回答中描述的算法进行的。您的具体问题是什么?看起来一个非常简单的算法就足够了。@Niklas B::实际上我希望我的程序应该使用最小步长和最小运算。比如,如果N是1000,我的程序应该使用小于20的步长和小于2100的运算。试着自己写一个!只需在循环中对数字求和。@Niklas B:他想要“并行”前缀求和算法。你在维基百科关于并行前缀求和的文章中实现了该算法吗?如果是这样的话,那么将其发布在这里或ideone上,我们将帮助您“显示输出、步骤以及每个步骤的操作/说明”部分。这是如何并行的?这完全是循序渐进的。我不知道OP为什么接受这个答案。回答很好,但是
x[k+2^d+1-1]
应该是x[k+2^(d+1)-1]
在这里和你链接到的CUDA文章中(我相信他们给出的代码图——我相信下标符号错误地丢失了)。你是正确的。我检查了Blelloch的文章,似乎NVIDIA文章是不正确的。在上述算法的向下扫描阶段,假设n=10,对于d=2,k=8,索引k+2 ^ -1>n。k+2^(d+1)–1>n也是如此。这将导致应用程序核心转储。我们应该如何处理n不是2的幂的情况?你需要用0来填充它,所以它是2的幂。我有点难以理解所有k=0到n–1乘2^(d+1)并行做什么。我得到了所有k=0到n-1部分的,但是与2^(d+1)
有什么关系呢?我知道d
来自outher循环,所以我当然可以计算2^(d+1)
,但是我应该怎么做,或者所用的关键字是什么意思?如果你能澄清这一点,那就太好了。谢谢我还实现了其他算法,比较了开放CL和线程与直接顺序执行,我发现Intel core i7 CPU已经做了一些重大改进。您还需要查看编译选项,如果您想要真正的顺序执行,请从编译中删除所有优化,即使这样,也很难打败顺序和,CPU在计算和方面非常高效,我不知道在运行时到底做了哪些优化,使其如此快速。
Enter the no. of elements in input array : 8
Enter element 1 : 1
Enter element 2 : 2
Enter element 3 : 3
Enter element 4 : 4
Enter element 5 : 5
Enter element 6 : 6
Enter element 7 : 7
Enter element 8 : 8
Output array :-
1, 3, 6, 10, 15, 21, 28, 36
for d = 0 to log2(n) – 1 do
for all k = 0 to n – 1 by 2^(d+1) in parallel do
x[k + 2^(d+1) – 1] = x[k + 2^d – 1] + x[k + 2^(d+1) – 1]
x[n – 1] = 0
for d = log2(n) – 1 down to 0 do
for all k = 0 to n – 1 by 2^(d+1) in parallel do
t = x[k + 2^d – 1]
x[k + 2^d – 1] = x[k + 2^(d+1) – 1]
x[k + 2^(d+1) – 1] = t + x[k + 2^(d+1) – 1]