Функция Fortran, возвращающая неверные значения
Эй, я работаю над программой на Фортране и столкнулся со странной проблемой. Когда я пытаюсь вывести некоторые значения массива непосредственно перед вызовом определенной подпрограммы, я получаю правильные значения. Затем я пытаюсь вывести некоторые значения из того же массива сразу же после запуска подпрограммы, и они равны 0. Я наконец выводю значения массива после подпрограммы, и значения возвращаются к ожидаемым значениям. Может ли кто-нибудь помочь мне понять, почему? Мой код ниже:
Во-первых, вызов подпрограммы в главной функции со значениями, которые я хочу вывести в операторах записи:
if (iter .eq. 5) then
write(*,*) 'vp vals: ',vp(0,23471), vp(0,23475)
end if
CALL GRID_DIVISION( &
& NPTMAX, DIM, TYPEMAX, NEIGHMAX, NPTC, GRIDLIMIT, &
& GRIDN, GRIDNUM, GRID, GNEIGH, XP, PTTYPE, TYPE, &
& GRIDP, TEMP_GRIDP, GNEIGHMAX, PAINT, VP, ITER, gridvel &
& )
if (iter .eq. 5) then
write(*,*) 'vp vals: ',vp(0,23471), vp(0,23475)
end if
Это вызывает следующую подпрограмму, из которой я опубликую только соответствующую часть:
SUBROUTINE GRID_DIVISION( &
& NPTMAX, DIM, TYPEMAX, NEIGHMAX, NPTC, GRIDLIMIT, &
& GRIDN, GRIDNUM, GRID, GNEIGH, XP, PTTYPE, TYPE, &
& GRIDP, TEMP_GRIDP, GNEIGHMAX, PAINT,VP,ITER, gridvel &
& )
IMPLICIT NONE
INTEGER, INTENT(IN) :: NPTMAX, DIM, TYPEMAX, NEIGHMAX, GNEIGHMAX
INTEGER, INTENT(IN) :: NPTC
INTEGER, INTENT(IN) :: GRIDLIMIT
INTEGER, INTENT(IN) :: GRIDN(0: DIM - 1)
INTEGER, INTENT(IN) :: GRIDNUM
INTEGER, INTENT(IN) :: PTTYPE(0: NPTMAX)
INTEGER, INTENT(IN) :: TYPE(0: TYPEMAX)
INTEGER, INTENT(INOUT) :: GRIDP(0: NPTMAX)
INTEGER, INTENT(INOUT) :: GNEIGH(1: GRIDLIMIT, 0: GNEIGHMAX)
REAL , INTENT(IN) :: GRID(1: GRIDLIMIT, 0: DIM - 1, 0: 1)
REAL , INTENT(IN) :: XP(0: DIM - 1, 0: NPTMAX)
REAL , INTENT(IN) :: VP(0: DIM - 1, 0: NPTMAX)
INTEGER, INTENT(INOUT) :: TEMP_GRIDP(0: NPTMAX)
INTEGER, INTENT(INOUT) :: PAINT(0:NPTMAX)
INTEGER, INTENT(INOUT) :: ITER
real, intent(inout) :: gridvel(GRIDNUM,0:1)
INTEGER :: II, JJ, KK
INTEGER :: DNUM
INTEGER :: GRIDXP
INTEGER :: SGRIDXP
INTEGER :: EGRIDXP
INTEGER :: SGRIDYP
INTEGER :: EGRIDYP
INTEGER :: SEARCH
INTEGER :: SCOUNT
INTEGER :: FCOUNT
INTEGER :: ERROR
INTEGER, PARAMETER :: CELL = 2
if (iter .eq. 5) then
write(*,*) 'vp vals: ',vp(0,23471), vp(0,23475)
end if
...
end subroutine
С большим количеством материала после этого раздела, который не выводится. Когда я запускаю код, мои выводы на итерации 5 для этого раздела:
vp vals: 75.00000 75.00000
vp vals: 0.00000000E+00 0.0000000E+00
vp vals: 75.00000 75.00000
Я просто не могу понять, почему мой массив VP не имеет значений в подпрограмме.
2 ответа
Я понял. VP был выделен как
VP(0:DIM,0:NPTMAX)
в основной программе и
VP(0:DIM-1,0:NPTMAX)
в подпрограмме! Это вызвало ошибку.
Ручная установка массивов явной формы a(0:N-1,0:M)
чрезвычайно подвержен ошибкам. Я предлагаю использовать массивы предполагаемой формы a(:,:)
передать аргументы. Кроме того, когда вы передаете массивы в качестве аргументов подпрограммам, верхняя и нижняя границы фактического аргумента не поддерживаются в вызове, если только нижняя граница не равна 1. Однако при передаче указателей нижняя и верхняя границы сохраняются. Например,
program main
use, intrinsic :: iso_fortran_env, only: &
stdout => OUTPUT_UNIT, &
compiler_version, &
compiler_options
! Explicit typing only
implicit none
real :: foo(10,10)
real, target :: bar(0:9,0:9)
real, pointer :: ptr(:,:) => null()
call peek_assumed_shape(foo, 'peek_assumed_shape: foo(10,10)')
call peek_assumed_shape(bar, 'peek_assumed_shape: bar(0:9,0:9)')
ptr => bar
call peek_pointer(ptr, 'peek_pointer: ptr => bar')
ptr(42:,42:) => bar
call peek_pointer(ptr, 'peek_pointer: ptr(42:,42:) => bar')
nullify( ptr )
write (stdout, '(/4a/)') &
'This file was compiled using compiler version ', compiler_version(), &
' and compiler options ', compiler_options()
contains
subroutine peek_assumed_shape(array, description)
! Calling arguments
real, intent (in) :: array(:,:)
character (len=*), intent (in) :: description
write (stdout, '(/a)') description
write (stdout, *) 'dim=1 ', lbound(array, dim=1), ubound(array,dim=1)
write (stdout, *) 'dim=2 ', lbound(array, dim=2), ubound(array,dim=2)
end subroutine peek_assumed_shape
subroutine peek_pointer(array, description)
! Calling arguments
real, pointer, intent (in) :: array(:,:)
character (len=*), intent (in) :: description
if (associated(array)) then
write (stdout, '(/a)') description
write (stdout, *) 'dim=1 ', lbound(array, dim=1), ubound(array,dim=1)
write (stdout, *) 'dim=2 ', lbound(array, dim=2), ubound(array,dim=2)
end if
end subroutine peek_pointer
end program main
возвращает следующее
peek_assumed_shape: foo(10,10)
dim=1 1 10
dim=2 1 10
peek_assumed_shape: bar(0:9,0:9)
dim=1 1 10
dim=2 1 10
peek_pointer: ptr => bar
dim=1 0 9
dim=2 0 9
peek_pointer: ptr(42:,42:) => bar
dim=1 42 51
dim=2 42 51
This file was compiled using compiler version GCC version 5.4.0 20160609 and compiler options -mtune=generic -march=x86-64 -O3 -Wall -std=f2008ts