【发布时间】:2021-10-22 10:24:01
【问题描述】:
#include <omp.h>
#include <stdio.h>
void prefix(int n, int A[n]){
//end of recursion
if(n==1) return;
int n2 = n/2;
//Array split
int L[n2];
int R[n-n2];
#pragma omp parallel for
for(int i=0; i<n2; i++){
L[i]=A[i];
}
#pragma omp parallel for
for(int i=n2; i<n-n2; i++){
R[i-n2]=A[i];
}
//recursion
#pragma omp task
prefix(n2,L);
#pragma omp task
prefix(n-n2,R);
#pragma omp taskwait
#pragma omp parallel for
for(int i = 0; i<n2; i++){
A[n2+i]=A[n2]+A[n2+i];
}
for(int i = 0; i<n; i++){
printf("%d\n",A[i]);
}
printf("END\n");
}
int main(){
int A[4] = {1,2,3,4};
prefix(4,A);
for(int i=0;i<4;i++){
printf("%d",A[i]);
}
}
输出: 1 结尾 32 结尾 1 4 结尾 16 结尾 32 结尾 16 0 结尾 1 2 6 7 结尾 第1267章
所以我知道部分递归和由于前半部分的 32 而被搞砸了。但我目前正在努力寻找原因。初始算法使用从 1 到 n 的数组。与范围有关吗?
感谢您的帮助。
编辑:
现在我明白了:
1 2 结尾 6684773 7864425 结尾 1 2 3 7 结尾 第1237章
什么原因导致前缀和计算失败?
现在解决了:
#include <omp.h>
#include <stdio.h>
void prefix(int n, int *A, int start, int end){
//end of recursion
if(n==1) return;
int n2 = n/2;
//recursion
#pragma omp task
prefix(n2,A, start, end-n2);
#pragma omp task
prefix(n-n2,A,end-n2+1, end);
#pragma omp taskwait
#pragma omp parallel for
for(int i = 0; i<n2; i++){
A[end-n2+1+i]=A[end-n2]+A[end-n2+1+i];
}
for(int i = 0; i<n; i++){
printf("%d\n",A[i]);
}
printf("END\n");
}
int main(){
int A[4] = {1,1,1,1};
prefix(4,A,0,3);
for(int i=0;i<4;i++){
printf("%d",A[i]);
}
}
【问题讨论】:
-
如果
n为零,您应该返回零,而不是A[0](在这种情况下,这是一个越界访问,假设零大小的数组是有意义的)。如果n为一,则可以返回A[0]。 -
prefix函数不应返回任何内容,因为对prefix的所有三个调用都忽略了返回值。将函数声明为void prefix(int n, int A[n]);,并将return A[0];更改为return;。 -
代码无法正确处理
n的奇数值。请记住,整数除法会向 0 截断。例如,如果n=3则L[n/2]和R[n/2]实际上是L[1]和R[1]。这是一个问题,因为n的起始值是4,所以递归调用是n=2,然后是n=1,1是奇数。 -
在函数顶部计算一次
n2 = n/2。这两个数组的长度将是n2和n - n2。请注意,如果n是偶数,n - n2将等于n2,如果n是奇数,则n2+1。 -
prefix函数到底应该做什么?请澄清一下。除了索引问题,使用本地数组(L,R)的递归调用对main中的数组A没有任何影响。
标签: c recursion openmp prefix-sum