指针阵列到一个不连续的数组部分

时间:2014-08-07 22:17:20

标签: arrays pointers fortran

我可以使用指向目标数组的不连续部分的指针数组吗?在以下程序中:

program test
  implicit none

  integer :: i
  integer, dimension(4), target :: orig
  integer, dimension(:), pointer :: ref

  orig = (/ (i , i = 1,4) /)

  ref(1:2) => orig(1:2)   
  ref(3:3) => orig(4:4)

  print *, 'orig = ', orig
  print *, 'ref = ', ref

end program test

我希望指针ref指向目标数组(/1,2,4/)的不连续部分orig。代码编译时没有警告,但是不需要输出:

code output:
 orig =            1           2           3           4
 ref =            4

看起来编译器强制指针指向连续的子部分,即使我首先指向索引1:2但编译器只强制指向4:4。结果,我在末尾的指针只指向一个条目。

我可以将条目(/1,2,4/)打包到另一个数组中然后连续使用它,但这对于大数据集来说不是有效的Fortran编码。你知道怎么做这个吗?

2 个答案:

答案 0 :(得分:5)

您的指针赋值具有所谓的边界重映射。 "整个"指针对象是指定的指针,但它给出了左侧括号中指示的边界。这使得您具有除1之外的下限,并且指针的等级与目标不同。当虚拟数组是显式或假定大小时,此功能类似于数组参数关联所具有的功能。

你不能指向目标数组的任意元素 - 目标中的元素必须是"常规" - 他们之间有一个持续的步伐。

作为重新打包的替代方法,您显然可以将这些索引存储在数组中,并使用整个目标和索引数组的组合来获取所需的行为,可能是通过将指针包装到整个目标和数组具有已定义赋值的派生类型中的索引。

答案 1 :(得分:0)

在“@IanH”建议之后,我实现了一个包装器,它只有指针和数据的指针,所有内容都在IN PLACE中完成,所以这应该更适合大数据。对于小数据集,我认为“@Vladimir F”的矢量索引理念更好,更具可读性。下面的代码通过了valgrind完整的memleak测试,我尝试了大数据集(6GB双精度)并且它不会复制数据。

module any_stride
  implicit none
  private
  ! ------------------------------------------------------------
  ! data = pointer to the contiguous 1D double precision array
  ! indx = pointer to the non-uniform indices
  ! example: for a stride where: 
  ! stride%data => (/ 1.0d0, 2.0d0, 3.0d0, 4.0d0 /)
  ! stride%indx => (/ 1, 4 /)
  ! is a wrapper around 1d data array with four elements
  ! that only elements 1 and 4 are visible to the outside world  
  !
  type stride
     private
     real*8, dimension(:), pointer, public :: data => null()
     integer, dimension(:), pointer, public :: indx => null()
   contains
     procedure :: assgn_from_scalar
     procedure :: assgn_from_array
     ! ... 
     ! ...
     ! ... add more overloaded procs if you want 
     generic :: assignment(=) => assgn_from_scalar &
          , assgn_from_array
     generic :: operator(+) => add_to_scalar &
          , add_to_array
     ! ... 
     ! ...
     ! ... add more overloaded procs if you want 
  end type stride

  public :: stride

contains

   subroutine assgn_from_scalar(this, rhs)
    implicit none
    class(stride), intent(inout) :: this
    real*8, intent(in) :: rhs

    ! local vars
    integer :: i

    do i = 1, size(this%indx)
       this%data(this%indx(i)) = rhs
    end do

    ! done here
  end subroutine assgn_from_scalar

  subroutine assgn_from_array(this, rhs)
    implicit none
    class(stride), intent(inout) :: this
    real*8, dimension(:), intent(in) :: rhs

    ! local vars
    integer :: i

    do i = 1, size(this%indx)
       this%data(this%indx(i)) = rhs(i)
    end do

    ! done here
  end subroutine assgn_from_array


  function add_to_scalar(lhs, rhs)
    implicit none
    class(stride), intent(in), target :: lhs
    real*8, intent(in) :: rhs
    class(stride), pointer :: add_to_scalar

    ! local vars
    integer :: i

    do i = 1, size(lhs%indx)
       lhs%data(lhs%indx(i)) = lhs%data(lhs%indx(i)) + rhs
    end do

    add_to_scalar => lhs

    ! done here
  end function add_to_scalar

  function add_to_array(lhs, rhs)
    implicit none
    class(stride), intent(in), target :: lhs
    real*8, dimension(:), intent(in) :: rhs
    class(stride), pointer :: add_to_array

    ! local vars
    integer :: i

    do i = 1, size(lhs%indx)
       lhs%data(lhs%indx(i)) = lhs%data(lhs%indx(i)) + rhs(i)
    end do

    add_to_array => lhs

    ! done here
  end function add_to_array

end module any_stride

! a little tester program
!
! COMMENT and UNCOMMENT after this line 
! when using the module in this file
!
program test
  use any_stride
  implicit none

  ! local vars
  integer :: i
  real*8, dimension(4), target :: data
  real*8, dimension(2) :: rhs = (/ 3.0d0, 6.0d0 /)
  integer, dimension(2), target :: indx
  type(stride) :: astride

  data = (/ 1.0d0, 2.0d0, 3.0d0, 4.0d0 /)
  indx = (/ 1, 4 /)
  astride = stride(data, indx)


  astride = astride + rhs
  print *, 'astride data= ', astride%data

  ! done here
end program test

值1和4仅添加到数组数据的第一个和最后一个条目。