我有一个嵌套循环,应该迭代一个N-dim立方体(直线,方形,立方体......)
到目前为止,我使用嵌套循环执行此操作,例如。 对于2D:
do i = 1,Ni
do j = 1,Nj
! do stuff with f(i,j)
enddo
enddo
或3D:
do i = 1,Ni
do j = 1,Nj
do k = 1,Nk
! do stuff with f(i,j,k)
enddo
enddo
enddo
我想用一个适用于每个可能的N维案例的构造替换这些嵌套循环。我怎么能在Fortran中这样做?在C ++中,可以使用迭代器。在Fortran中有这样的东西吗?
我正在考虑写一个类,它的工作类似于机械的n维计数器(即如果我们每个维数计算3个):
0,0,0,0,0
1,0,0,0,0
2,0,0,0,0
0,1,0,0,0
1,1,0,0,0
与嵌套for循环相比,这会有点快吗?你们有更好的想法吗?
答案 0 :(得分:1)
这可能是最简单的......
另外,您会注意到数组的索引顺序是相反的。 Fortran在左边最快,所以它与C相反。
当你调用它时,它通过检查模块的接口,使用哪一个与你自动发送给它的数组维度相匹配。
MODULE Stuff
IMPLICIT NONE
PUBLIC MY$Work
INTERFACE MY$Work
MODULE PROCEDURE MY$Work1D, MY$Work2D, MY$Work3D
END INTERFACE
PRIVATE
CONTAINS
!~~~~~~~~~~
SUBROUTINE MY$Work1d(Array, F_of_Array)
REAL, DIMENSION(:), INTENT(IN ) :: Array
REAL, DIMENSION(:), INTENT(INOUT) :: F_of_Array
INTEGER :: I
!DIR$ DO SIMD
do i = LBOUND(Array,1) ,UBOUND(Array,1)
! do stuff with f(i)
enddo
RETURN
END SUBROUTINE MY$Work1d
!~~~~~~~~~~
SUBROUTINE MY$Work2d(Array, F_of_Array)
REAL, DIMENSION(:,:), INTENT(IN ) :: Array
REAL, DIMENSION(:,:), INTENT(INOUT) :: F_of_Array
INTEGER :: I,J
!DEC$ UNROLL_AND_JAM
do j = LBOUND(Array,2) ,UBOUND(Array,2)
do i = LBOUND(Array,1) ,UBOUND(Array,1)
! do stuff with f(i,j)
enddo
enddo
RETURN
END SUBROUTINE MY$Work2d
!~~~~~~~~~~
SUBROUTINE MY$Work3d(Array, F_of_Array)
REAL, DIMENSION(:,:,:), INTENT(IN ) :: Array
REAL, DIMENSION(:,:,:), INTENT(INOUT) :: F_of_Array
INTEGER :: I,J,K
!DEC$ UNROLL_AND_JAM
do k = LBOUND(Array,3) , UBOUND(Array,3)
do j = LBOUND(Array,2) ,UBOUND(Array,2)
do i = LBOUND(Array,1) ,UBOUND(Array,1)
! do stuff with f(i,j,k)
enddo
enddo
enddo
RETURN
END SUBROUTINE MY$Work3d(Array, F_of_Array)
END MODULE Stuff
PROGRAM XX
USE STUFF
...
所以你可以有一个3D数组并执行此操作
DO K = 1, nk
CALL MY$WORK(Array(:,:,k), ResultArray(:,:,K) )
ENDDO
那将使用2D版本并在所有K-case上循环...
答案 1 :(得分:1)
我决定使用超级索引。我的尺寸大小限制为2的幂。这允许我使用bitshift操作和定期添加。希望这比面向对象的计数器更快。
pure function supI(j, k, n) result(vec)
implicit none
integer*8, intent(in) :: j
integer*8 :: copy
integer*4, intent(in) :: k, n
integer*4 :: vec(n), x, mask
! transforms super index j to a n-dimensional iteration,
! where each dimension has a range of 2^k
! mask to extract left most indicies
mask = ISHFT(1, k) -1
copy = j
do x = 1,n
! extract current value using mask
vec(x) = and(copy, mask)
! shift to next value
copy = ISHFT(copy, -k)
enddo
end function supI
每个维度中包含4个的3d计数器将如下所示:
do j = 0,64
write(*,*) supI(j, 2, 3)
enddo
编辑:与没有优化的循环速度相比,它并不坏:大约20%的时间,但如果我使用优化器,它比嵌套循环慢得多。