سؤال

I'm in the process of learning fortran (90), with past experience in c and python. I'm reading about arrays (it's interesting to see that so much of the python array behavior is based on that of fortran); and I was wondering, is there ever a reason to assign an allocatable array without a deferred size? And is it possible to defer the size without using allocatable -- if so, how?

e.g.

REAL, DIMENSION(:) :: arr1
REAL, ALLOCATABLE, DIMENSION(20) :: arr2
هل كانت مفيدة؟

المحلول

Array terminology can be a bit daunting in Fortran. The first thing to realize is the difference between an actual argument, a variable for which a procedure has to allocate some memory, and a dummy argument, placeholders for actual arguments passed along by the calling procedure. If a variable is in a procedure's argument list, it is a dummy argument.

So, as for actual arguments, there are two kinds of arrays:

  • explicit-shape, e.g. <type> :: A(3,6)
  • deferred-shape, e.g. <type>, <allocatable|pointer> :: A(:,:,:)

A deferred shape must have an allocatable or pointer attribute.

When it comes to dummy arguments, there are also two kinds of arrays:

  • assumed-size, e.g. <type> :: A(4,5,*), B(1:2,4:*), C(m,n)
  • assumed-shape, e.g. <type> :: A(:,4:)

The actual and dummy arguments are not related in any way, so don't mix them. Also note that there exist something called automatic arrays, these look exactly like assumed-size arrays with dummy variables as sizes (C(m,n)), but don't appear in the argument list, so they are not dummy arguments.

For the assumed-size array, the last dimension's upper bound should be left unspecified (the *), other than that lower+upper bounds can be specified, including variables passed along to the procedure. Think of it as an array for which you re-specify the entire layout, irrespective of the actual argument. This allows you to do things like:

program toby
integer, parameter :: n = 10
real :: a(n**3)
call my_sub(a,n)
end program

subroutine my_sub(a,n)
integer, intent(in) :: n
real, intent(inout) :: a(n,n,*)
...
end subroutine

The other dummy argument, the assumed-shape, only allows you to specify lower bounds, as it gets its size info from the actual argument. This means you also can't redefine the dimensionality, and you need an explicit interface (e.g. via a module). This makes it more stringent, and also unnecessary to pass along size information with the array.

program toby
integer, parameter :: n = 10
real :: a(n,n,n)
call my_sub(a)

contains

subroutine my_sub(a)
real, intent(inout) :: a(:,:,:)
integer :: n
n = size(a,1)
...
end subroutine
end program

You can read about it in much more detail here I find it to be an ideal reference.

Last but not least, since you mention python, don't be to eager to apply python-like array slicing in Fortran, as it can cause the use of temporary arrays, which can slow down the program. You can use -fcheck=array-temps with gfortran to warn for that. Furthermore, even though elemental operations on whole arrays are recommended for efficiency (e.g. A=A+1 in using arrays efficiently), don't misinterpret that as "writing very concise code is good for efficiency". The latter is of course not (necessarily) true.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top