我可以使用指向目标数组的不连续部分的指针数组吗?在以下程序中:
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编码。你知道怎么做这个吗?
答案 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仅添加到数组数据的第一个和最后一个条目。