问题
I have a Fortran 90 program that is of the structure shown below. The step compute the 2D array myMatrix(1:N,1:N)
in the subroutinne A
is expensive. It depends only on the global variable N
and it needs to be computed only once; the "other steps" in the subroutine will not change the value of myMatrix. Currently, myMatrix
will be calculated whenever the subroutine is called.
Is there a way to write the program in a way that the 2D array myMatrix
is calculated only once?
module constants
integer :: N
end module constans
module A_module
use constants
contains
subroutine A
! compute the 2D real array myMatrix(1:N,1:N)
! other steps that use myMatrix
end subroutine A
end module A_module
program main
use constants
use A_module
integer :: k
do k = 1,10000
call A
end do
end program main
回答1:
Sure. Definite an init_a_matrix
subroutine that initializes the matrix outside of the do loop.
subroutine init_a_matrix
! Do initialization here
end subroutine init_a_matrix
Then you have
call init_a_matrix
do k = 1,10000
call A
end do
If you want to eliminate the redundant initialization of myMatrix
in the subroutine A (since it only needs to be calculated once, upon the initial call of the subroutine), you can use the SAVE
attribute and a LOGICAL
flag. In subroutine A
you do,
logical :: init_flag = .false.
real, save :: matrix_a(n,n)
if (init_flag .eqv. .false.) then
! Initialize matrix_a on the first call to the subroutine and reset init_flag.
init_flag = .true.
end if
回答2:
If myMatrix
is an unsaved, local variable of the subroutine A
, then it will be necessary to recalculate its values on each entry of the subroutine: unsaved local variables become undefined when the subroutine completes execution.
However, there are a number of approaches to reuse the variable:
- make it a saved local variable: saved local variables retain their definition
- have it as a dummy argument, not a local variable (argument association): its definition comes from the caller
- have it as some other form of non-local variable (other forms of association): its definition comes from another place
If it's a saved variable, compute it on the first entry to the subroutine and retains its definition on subsequent calls:
subroutine A
<declaration>, save :: mymatrix
logical, save :: first_entry = .TRUE.
if (first_entry) then
! set up mymatrix
first_entry = .FALSE.
end if
! ...
end subroutine A
You can do much the same with mymatrix
a module/host variable. You can either use the first_entry
saved indicator or rely on the user (as in evets's answer) having an extra setup step:
module A_module
use constants
<declaration> myMatrix ! Example with host association, automatically saved
contains
subroutine A
! myMatrix is reused, either set up by a distinct call or on first entry
! other steps that use myMatrix
end subroutine A
end module A_module
Or you can have the variable as a dummy argument:
mymatrix_actual = ...
do k = 1,10000
call A(mymatrix_actual) ! A now has the dummy variable
end do
来源:https://stackoverflow.com/questions/62855537/initialization-of-2d-arrays-within-subroutines