Fortran 子例程返回错误值
Fortran subroutine returning wrong values
嘿,我正在研究一个堡垒运行 程序并且 运行 遇到了一个奇怪的问题。当我尝试在调用特定子例程之前直接输出数组的某些值时,我得到了正确的值。然后我尝试在启动子例程时输出同一数组的一些值,它们为 0。我最终在子例程之后输出数组的值,并且这些值返回到预期值。谁能帮我理解为什么?我的代码如下:
首先,在主函数中调用子程序,在write语句中输出我想要的值:
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
这是在调用以下子例程,我将只post相关部分:
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在子程序中没有值。
我明白了。 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
returns以下
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
嘿,我正在研究一个堡垒运行 程序并且 运行 遇到了一个奇怪的问题。当我尝试在调用特定子例程之前直接输出数组的某些值时,我得到了正确的值。然后我尝试在启动子例程时输出同一数组的一些值,它们为 0。我最终在子例程之后输出数组的值,并且这些值返回到预期值。谁能帮我理解为什么?我的代码如下:
首先,在主函数中调用子程序,在write语句中输出我想要的值:
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
这是在调用以下子例程,我将只post相关部分:
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在子程序中没有值。
我明白了。 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
returns以下
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