基于求和的 OpenMP
OpenMP over Summation
我一直在尝试将 OpenMP 应用于两个嵌套循环内的简单求和运算,但到目前为止它产生了不正确的结果。我一直在 here and here, also in here 中四处张望。所有人都建议使用 reduction
子句,但它不适用于我的情况,因为它会产生导致 segmentation fault
.
的非常大的数字
我也试过here and my own question 中的这种方式,已经解决了。两者都不使用 reduction
,只是将求和变量设置为 shared
,但它也会产生不正确的结果。有什么我想念的吗?什么时候使用 reduction
而不在面对求和运算时使用它?
使用 reduction
子句的代码
index = 0
!$OMP PARALLEL DO PRIVATE(iy,ix) REDUCTION(:+index)
do iy = 1, number(2)
do ix = 1, number(1)
index = index + 1
xoutput(index)=xinput(ix)
youtput(index)=yinput(iy)
end do
end do
!$OMP END PARALLEL DO
不使用 reduction
子句的代码
index = 0
!$OMP PARALLEL DO PRIVATE(iy,ix) SHARED(index)
do iy = 1, number(2)
do ix = 1, number(1)
index = index + 1
xoutput(index)=xinput(ix)
youtput(index)=yinput(iy)
end do
end do
!$OMP END PARALLEL DO
我认为您对 reduction
子句的作用有误解...
REDUCTION(+:index)
意味着,你将得到正确的总和index
最终。在迭代的每一步中,每个胎面都会有不同的版本和不同的值!因此,缩减不适合在并行部分管理数组索引。
让我试着说明一下...
下面循环
!$OMP PARALLEL DO PRIVATE(iy) REDUCTION(+:index)
do iy = 1, number(2)
index = index + 1
end do
!$OMP END PARALLEL DO
(或多或少)等同于
!$OMP PARALLEL PRIVATE(iy, privIndex) SHARED(index)
!$OMP DO
do iy = 1, number(2)
privIndex = privIndex + 1
end do
!$OMP END DO
!$OMP CRITICAL
index = index + privIndex
!$OMP END CRITICAL
!$OMP END PARALLEL
您可以看到,在循环期间,所有线程都处理该线程私有的不同变量 privIndex
,并计算局部(部分)总和。最后,取总和,使用 critical
部分来避免竞争条件。
这可能不是编译器所做的,但它让您了解缩减是如何工作的:在第一个循环中的任何时候 privIndex
都不会对应于您在串行版本中期望的正确索引.
正如 Vladimir 在他的评论中建议的那样,您可以直接计算索引,因为您只是在内循环中递增它:
!$OMP PARALLEL DO PRIVATE(iy,ix, index)
do iy = 1, number(2)
do ix = 1, number(1)
index = (iy-1)*number(1) + ix
xoutput(index)=xinput(ix)
youtput(index)=yinput(iy)
end do
end do
!$OMP END PARALLEL DO
我一直在尝试将 OpenMP 应用于两个嵌套循环内的简单求和运算,但到目前为止它产生了不正确的结果。我一直在 here and here, also in here 中四处张望。所有人都建议使用 reduction
子句,但它不适用于我的情况,因为它会产生导致 segmentation fault
.
我也试过here and my own question reduction
,只是将求和变量设置为 shared
,但它也会产生不正确的结果。有什么我想念的吗?什么时候使用 reduction
而不在面对求和运算时使用它?
使用 reduction
子句的代码
index = 0
!$OMP PARALLEL DO PRIVATE(iy,ix) REDUCTION(:+index)
do iy = 1, number(2)
do ix = 1, number(1)
index = index + 1
xoutput(index)=xinput(ix)
youtput(index)=yinput(iy)
end do
end do
!$OMP END PARALLEL DO
不使用 reduction
子句的代码
index = 0
!$OMP PARALLEL DO PRIVATE(iy,ix) SHARED(index)
do iy = 1, number(2)
do ix = 1, number(1)
index = index + 1
xoutput(index)=xinput(ix)
youtput(index)=yinput(iy)
end do
end do
!$OMP END PARALLEL DO
我认为您对 reduction
子句的作用有误解...
REDUCTION(+:index)
意味着,你将得到正确的总和index
最终。在迭代的每一步中,每个胎面都会有不同的版本和不同的值!因此,缩减不适合在并行部分管理数组索引。
让我试着说明一下...
下面循环
!$OMP PARALLEL DO PRIVATE(iy) REDUCTION(+:index)
do iy = 1, number(2)
index = index + 1
end do
!$OMP END PARALLEL DO
(或多或少)等同于
!$OMP PARALLEL PRIVATE(iy, privIndex) SHARED(index)
!$OMP DO
do iy = 1, number(2)
privIndex = privIndex + 1
end do
!$OMP END DO
!$OMP CRITICAL
index = index + privIndex
!$OMP END CRITICAL
!$OMP END PARALLEL
您可以看到,在循环期间,所有线程都处理该线程私有的不同变量 privIndex
,并计算局部(部分)总和。最后,取总和,使用 critical
部分来避免竞争条件。
这可能不是编译器所做的,但它让您了解缩减是如何工作的:在第一个循环中的任何时候 privIndex
都不会对应于您在串行版本中期望的正确索引.
正如 Vladimir 在他的评论中建议的那样,您可以直接计算索引,因为您只是在内循环中递增它:
!$OMP PARALLEL DO PRIVATE(iy,ix, index)
do iy = 1, number(2)
do ix = 1, number(1)
index = (iy-1)*number(1) + ix
xoutput(index)=xinput(ix)
youtput(index)=yinput(iy)
end do
end do
!$OMP END PARALLEL DO