Fortran 2003 - 数组操作 - 是否有更快/更好的方法来执行此操作,不涉及DO循环?

时间:2014-03-04 12:57:28

标签: arrays fortran fortran2003

我有一个问题,涉及使用一个小的2级数组(下面的代码中的array2)来保存一个更大的rank 4数组(下面的array1)的一些元素的有序列表。目前,我的一个步骤涉及使用DO循环,我想知道是否可以使用某种“阵列到阵列”操作一步完成此操作?在我写的主要代码中,我发现尽可能使用这种“阵列到阵列”操作会导致显着的速度增加。我觉得这是一个简单的问题,但我看不到解决方案或在网上找到一个。我很感激任何帮助!以下代码是问题的简化模型,但包含基本功能。感谢。

PROGRAM vec_array

IMPLICIT none

INTEGER :: i,j,k,l,cnt
INTEGER :: array1(-1:1, -2:2, -2:2, 3:6)
INTEGER :: array2(5,4)

! Set up arbitrary array of values in 'large' array
cnt=0
DO i=-1,1,1
  DO j=-2,2,1
    DO k=-2,2,1
      DO l=3,6,1

        cnt=cnt+2*l
        array1(i,j,k,l)=cnt

      END DO
    END DO
  END DO
END DO

! array2 holds an ordered list of array1 elements 
array2(1,:)=[-1, 2,-2, 6]
array2(2,:)=[ 0, 1, 2, 3]
array2(3,:)=[-1,-2,-2, 4]
array2(4,:)=[ 1, 2, 2, 5]
array2(5,:)=[-1,-2,-2, 3]

! This is the key step here - is there another way to do this, 
! potentially faster, that does not involve a DO-loop?
DO i=1,5,1
  array1( array2(i,1),array2(i,2),array2(i,3),array2(i,4) )=i
END DO

DO i=-1,1,1
  DO j=-2,2,1
    DO k=-2,2,1
      DO l=3,6,1

        WRITE(*,*) i,j,k,l,array1(i,j,k,l)

      END DO
    END DO
  END DO
END DO

END PROGRAM

1 个答案:

答案 0 :(得分:0)

有一点:我认为你真正的问题要大得多吗?这些微小的阵列适合缓存的最小圈子,我认为你不会通过花哨的代码重写获得更多的性能。如果它更大,你真的需要分析代码以找到瓶颈,然后花费太多时间重写代码以获得速度。

有一点需要注意,也许有点偏离主题,就是你以C顺序嵌套循环(其中内存中彼此接近的数据仅在最后一个索引中不同)。但Fortran以相反的方式组织其数组,其中内存中彼此接近的数据仅在第一个索引中不同。您当前组织array1的方式是最糟糕的方式,其中最内层的循环涉及内存中最大的进步。最好养成安排数据和嵌套循环以尽可能多地访问连续内存的习惯。