Sam*_*Tan 5 fortran multidimensional-array dynamic-memory-allocation
这有点复杂; 我欢迎任何关于如何提高问题清晰度的意见.
好吧,说我有一个数组:
real, allocatable :: A(:,:,:)
Run Code Online (Sandbox Code Playgroud)
我想在使用它之前分配它.第三维的大小是否可能取决于第二维的大小?
例如
do i=1,n
allocate(A(3,i,i**2))
end do
Run Code Online (Sandbox Code Playgroud)
显然以上都行不通.我想最终得到一个带有形状的数组(或一组数组)
(3,1,1), (3,2,4), (3,3,9), ... (3, n, n^2)
Run Code Online (Sandbox Code Playgroud)
其中第三维的大小是第二维的大小的平方.
我对依赖维度大小的规则有点复杂,但如果可以进行平方,我可以做其余的事情.
这可能吗?如果是这样,我如何在Fortran中实现它?
会有什么shape(A)
回报?那会很有趣.
我的另一种选择是分配到所需的最大尺寸,并注意只在计算中使用某些元素,即
allocate(A(3,n,n**2))
Run Code Online (Sandbox Code Playgroud)
虽然我现在对记忆并不苛刻,但我希望有良好的编程习惯.无论如何,这是一个有趣的问题.
谢谢.
编辑:
如果维度的大小取决于另一维度中元素的值?
在下面的答案中,两个维度中数组的大小取决于B的索引.我想要的是某些东西
type myarray
real :: coord(3)
integer,allocatable :: lev(:)
integer, allocatable :: cell(:)
endtype myarray
type(myarray), allocatable :: data
allocate(data(m))
allocate(data%lev(n))
forall (j=1:n) !simple now, for argument's sake
lev(j)=j
endforall
! I was thinking of using a FORALL loop here, but the errors returned
! suggested that the compiler (gfortran) didn't expect IF blocks and ALLOCATE
! statements in a FORALL block
do i=1,m
do j=1,n
allocate(data(i)%cell(lev(j)**2))
enddo
enddo
Run Code Online (Sandbox Code Playgroud)
你理解我的意思?但是当程序试图分配已经分配的变量时,例如当i=1
它分配时,程序就会崩溃data(1)%cell(1)
,然后尝试分配data(1)%cell(2)
...呃哦.我想要的是:
每个data(i)
都有一个lev(j)
值数组,j
从1到n运行,对于每个lev(j)
值,我们有一个cell
大小为lev
^ 2的值.请注意,这些cell
的是为每一个独特data(i)
和每个lev
,而特定的大小cell
取决于相应lev
的值,并可能相应data(i)
也.
我是否必须在派生类型中使用派生类型?
是的,您可以使用派生类型来完成此任务:
TYPE array
REAL,DIMENSION(:,:,:),ALLOCATABLE :: A
ENDTYPE array
INTEGER :: i
INTEGER,PARAMETER :: n=10
TYPE(array),DIMENSION(:),ALLOCATABLE :: B
ALLOCATE(B(n))
DO i=1,n
ALLOCATE(B(i)%A(3,i,i*i))
WRITE(*,*)SHAPE(B(i)%A)
ENDDO
END
Run Code Online (Sandbox Code Playgroud)
该方法允许阵列B的每个元素是不同形状的多维阵列.
该程序的输出符合预期:
3 1 1
3 2 4
3 3 9
3 4 16
3 5 25
3 6 36
3 7 49
3 8 64
3 9 81
3 10 100
Run Code Online (Sandbox Code Playgroud)
编辑:进一步回答OP的编辑问题.是的,看起来你需要做这样的事情,使用嵌套派生类型(比较你的代码示例来弄清楚你做错了什么):
integer,parameter :: m=3,n=5
type cellarray
integer,dimension(:),allocatable :: c
endtype cellarray
type myarray
integer,allocatable :: lev(:)
type(cellarray),dimension(:),allocatable :: cell
endtype myarray
type(myarray),dimension(:),allocatable :: B
allocate(B(m))
! Allocate and assign lev and cell:
do i=1,m
allocate(B(i)%lev(n))
allocate(B(i)%cell(n))
do j=1,n
B(i)%lev(j)=j
enddo
enddo
! Based on value of lev, allocate B%cell%c:
do i=1,m
do j=1,n
allocate(B(i)%cell(j)%c(B(i)%lev(j)**2))
enddo
enddo
! Print out to check that it works:
do j=1,n
write(*,*)j,B(1)%lev(j),SIZE(B(1)%cell(j)%c)
enddo
end
Run Code Online (Sandbox Code Playgroud)
用gfortran 4.6.2尝试了这个.它产生预期的输出:
1 1 1
2 2 4
3 3 9
4 4 16
5 5 25
Run Code Online (Sandbox Code Playgroud)