Fortran 将多维数组作为一维数组传递的最佳方法

Fortran 将多维数组作为一维数组传递的最佳方法,fortran,Fortran,我有一个子例程,它填充任意长度的秩1数组 subroutine populate_array_1D(array) implicit none integer, dimension(:), intent(out) :: array array(:) = 1 end subroutine populate_array_1D 现在我想使用重载来修改这个例程,以接受更高维度的数组 interface populate_array module procedure pop

我有一个子例程,它填充任意长度的秩1数组

subroutine populate_array_1D(array)
    implicit none
    integer, dimension(:), intent(out) :: array
    array(:) = 1
end subroutine populate_array_1D
现在我想使用重载来修改这个例程,以接受更高维度的数组

interface populate_array
    module procedure populate_array_1D, populate_array_2D, populate_array_3D
end interface populate_array
我想做的是将高维子程序引用回1D子程序

到目前为止,我的想法是:

  • 对阵列进行切片,并逐个传递切片:

    subroutine populate_array_2D(array)
        implicit none
        integer, dimension(:,:), intent(out) :: array
        integer :: i
        do i = lbound(array, 2), ubound(array, 2)
            call populate_array_1D(array(:, i))
        end do
    end subroutine populate_array_2D
    
  • 创建一个新的自动1D阵列,然后使用
    重塑

    subroutine populate_array_3D(array)
        implicit none
        integer, dimension(:,:,:), intent(out) :: array
        integer :: tmp_array(size(array))
        call populate_array_1D(tmp_array)
        array = reshape(tmp_array, shape(array))
    end subroutine populate_array_3D
    
  • 假设,如本例所示,任何一个版本的结果都可以,我只担心性能。(我可能应该补充一点,我不能仅仅制作一个
    元素
    子例程,因为它不能是

    或者有更好的版本,我可以将多维数组传递到一个子例程中,假装它是1D数组


    (最终,我想用一个PRNG来代替对
    随机数的调用,该PRNG在不同的编译器和/或机器之间尽可能具有确定性,假设它们使用相同的种子。)

    正如francescalus指出的,基本过程可能是不纯净的(从Fortran 2008开始)

    或者,您可以使用Fortran固有的C互操作性 以获得对2D阵列内存位置的低级别访问。以下子例程生成指向2D数组的1D指针:

    subroutine populate_array_2D(array)
        use iso_c_binding, only: C_F_POINTER, C_LOC
    
        integer, dimension(:,:), target, contiguous, intent(out) :: array
    
        integer, dimension(:), pointer :: ptr_1d
    
        call C_F_POINTER (C_LOC(array), ptr_1d, [size(array)])
        call populate_array_1D(ptr_1d)
    end subroutine populate_array_2D
    
    编辑: 对
    c\u f\u指针的调用可以替换为
    指针中的等效绑定重新映射列表:
    
    ptr_1d(1:大小(数组))=>array

    (尽管使用ifort18进行编译时给出了一个错误,即这不是Fortran 2008的有效版本)。

    正如francescalus指出的,基本过程可能是不纯净的(从Fortran 2008开始)

    或者,您可以使用Fortran固有的C互操作性 以获得对2D阵列内存位置的低级别访问。以下子例程生成指向2D数组的1D指针:

    subroutine populate_array_2D(array)
        use iso_c_binding, only: C_F_POINTER, C_LOC
    
        integer, dimension(:,:), target, contiguous, intent(out) :: array
    
        integer, dimension(:), pointer :: ptr_1d
    
        call C_F_POINTER (C_LOC(array), ptr_1d, [size(array)])
        call populate_array_1D(ptr_1d)
    end subroutine populate_array_2D
    
    编辑: 对
    c\u f\u指针的调用可以替换为
    指针中的等效绑定重新映射列表:
    
    ptr_1d(1:大小(数组))=>array

    (尽管使用ifort18编译时给出了一个错误,即这不是有效的Fortran 2008)。

    元素子例程可能是不纯净的。哇,我不知道您可以指定
    不纯净元素
    。谢谢@francescalusElemental子例程可以是不纯净的。哇,我不知道你可以指定
    不纯净元素
    。感谢@francescalus
    错误:C_LOC(1)处的参数X应具有指针或目标属性
    ,但假设
    数组
    是连续的,为什么不同时给它
    连续
    目标
    属性,这样就可以使用数组边界重新映射直接指向它的
    ptr_1d
    ptr_1d(1:size(array))=>array
    关于
    target
    属性,您是对的,谢谢您的关注。(iPort不提供)但指针的绑定重新映射列表不符合标准。我最初打算提到这一点,但我忘了。不,您还没有阅读关于这个问题的标准。我在你的帖子中添加了一个编辑,它充实了我的想法,并在iPort和gfortran上进行了编译。您在编辑中忘记了
    rank2_数组
    上的
    continuous
    属性。正如@user5713492所指出的,秩-2数组可能是边界重新映射指针赋值的目标,只要它只是连续的。但这似乎需要花费大量精力来避免
    整数数组(*)
    错误:参数X位于(1)to C_LOC应具有指针或目标属性
    ,但假设
    数组
    是连续的,为什么不同时赋予它
    连续
    目标
    属性,以便使用数组边界重新映射直接指向
    ptr_1d
    ptr_1d(1:size(array))=>array
    关于
    target
    属性,您是对的,谢谢您的关注。(iPort不提供)但指针的绑定重新映射列表不符合标准。我最初打算提到这一点,但我忘了。不,您还没有阅读关于这个问题的标准。我在你的帖子中添加了一个编辑,它充实了我的想法,并在iPort和gfortran上进行了编译。您在编辑中忘记了
    rank2_数组
    上的
    continuous
    属性。正如@user5713492所指出的,秩-2数组可能是边界重新映射指针赋值的目标,只要它只是连续的。但这似乎需要花费大量精力来避免
    整数数组(*)