这是一个用于矩阵向量乘法的Fortran子程序。它可能在很多方面都是过时的和低效的,但是现在我只是试图让它与OpenACC指令一起工作,而我正试图找出减少的工作方式:
subroutine matrmult(matrix,invec,outvec,n)
integer:: n
real*8, intent(in):: matrix(n,n), invec(n)
real*8, intent(out) :: outvec(n)
real*8 :: tmpmat(n,n)
real*8 :: tmpscl
integer :: i,j,k
!$acc declare create(matrix, invec, outvec, tmpmat)
outvec = 0.d0
!$acc update device(matrix, invec, tmpmat, outvec)
!$acc parallel
!$acc loop gang
do j=1,n
!$acc loop vector
do i=1,n
tmpmat(i,j) = matrix(i,j)*invec(j)
enddo
enddo
!$acc loop vector reduction(+:tmpsclr)
do j=1,n
tmpsclr = 0.d0
do i=1,n
tmpsclr = tmpsclr+tmpmat(j,i)
enddo
outvec(j) = tmpsclr
enddo
!$acc end parallel
!$acc update host(outvec)
end subroutine
此代码实际上给出了正确的结果。但是当我在最后一个循环上尝试一个帮派/矢量组合时,就像这样:
!$acc loop gang reduction(+:tmpsclr)
do j=1,n
tmpsclr = 0.d0
!$acc loop vector
do i=1,n
tmpsclr = tmpsclr+tmpmat(j,i)
enddo
outvec(j) = tmpsclr
enddo
结果回来都错了。对outvec
的大多数元素而非全部元素看起来总和不完整。无论我在哪里放置reduction
子句,无论是使用帮派还是向量,都是这种情况。更改位置会更改结果,但永远不会给出正确的结果。
我在一个简单的测试中得到的结果如下。 matrix
为10x10且全部为1,invec
为1,2,3,... 10。所以outvec
的元素应该只是invec
,55中元素的总和。如果我运行代码的gang / vector版本,outvec
的每个元素都是1,不是55.如果我用向量来减少,那么我得到了正确答案,55。这继续工作直到我超过90个元素。当我到达91时,outvec
的每个元素应该等于4186.但只有最后一个元素是,而所有其余元素都等于4095(1到90的总和)。随着元素数量的增加,值的变化和与正确答案的差异变得更糟。
我显然不明白减少是如何运作的。谁能解释一下?