Я получаю странную ошибку при компиляции своего кода симуляции, написанного на Фортране 90, я надеялся получить какую-нибудь помощь при любой возможности. Я использую ifort версии 18.0.3.
Прежде чем рассказать о проблеме, вот что у меня работает правильно:
Ниже module prng
- генератор псевдослучайных чисел (он на Фортране 77, но я проверил его на случай каких-либо проблем совместимости, он отлично работает!):
module prng
implicit none
contains
real*8 function genrand_real( ir )
implicit real*8 (a-h,o-z)
integer, intent(inout) :: ir
parameter(da=16807.d0,db=2147483647.d0,dc=2147483648.d0)
ir = abs(mod(da*ir,db)+0.5d0)
genrand_real = dfloat(ir)/dc
return
end function genrand_real
end module prng
Я также создал модуль для объявления семени:
module seed
implicit none
type mod_seed
integer :: seedvalue
end type mod_seed
end module seed
Чтобы использовать начальное значение, сначала нужно объявить type(mod_seed) :: seedval
, затем genrand_real(seedval%seedvalue)
возвращает действительное значение в (0,1).
Пока все вышеперечисленное работает нормально! Ниже приведено то, что я пытаюсь реализовать, в основном я принял функцию отклонения Гаусса, function gauss_dev() result(harvest)
, из Числовых рецептов на Фортране (стр. 280), см. Исходный код ниже:
module moves
use prng
use seed
implicit none
contains
function gauss_dev() result(harvest)
implicit none
real(kind=8) :: harvest
real(kind=8) :: rsq,v1,v2
real(kind=8), save :: g
logical, save :: gauss_stored = .false.
if (gauss_stored) then
harvest = g
gauss_stored = .false.
else
do
v1 = genrand_real(seedval%seedvalue)
v2 = genrand_real(seedval%seedvalue)
v1 = 2.0*v1-1.0
v2 = 2.0*v2-1.0
rsq = v1**2 + v2**2
if (rsq > 0.0 .and. rsq < 1.0) exit
enddo
rsq = sqrt(-2.0*log(rsq)/rsq)
harvest = v1*rsq
g = v2*rsq
gauss_stored = .true.
endif
end function gauss_dev
! also other subroutines that calls gauss_dev()
end module moves
seedval%seedvalue
инициализируется
subroutine read_iseed(seedval,IN_ISEED)
use prng
use seed
type (mod_seed), intent(inout) :: seedval
character(len=80) :: IN_ISEED
integer :: i
call system('od -vAn -N4 -td4 < /dev/urandom > '//trim(IN_ISEED))
open(unit=7,file=trim(IN_ISEED),status='old')
read(7,*) i
close(7)
seedval%seedvalue = abs(i)
return
end
Когда я компилирую код, я получаю сообщение об ошибке: error #6404: This name does not have a type, and must have an explicit type. [SEEDVAL]
, это ожидается, так как seedvalue
должен быть объявлен перед вызовом!
Поскольку seedvalue
переназначается в prng
, интуитивно я бы использовал опцию intent(inout)
. И вот мое исправление:
module moves
use prng
use seed
implicit none
contains
function gauss_dev() result(harvest)
implicit none
type (mod_seed), intent(inout) :: seedval
real(kind=8) :: harvest
real(kind=8) :: rsq,v1,v2
real(kind=8), save :: g
logical, save :: gauss_stored = .false.
if (gauss_stored) then
harvest = g
gauss_stored = .false.
else
do
v1 = genrand_real(seedval%seedvalue)
v2 = genrand_real(seedval%seedvalue)
v1 = 2.0*v1-1.0
v2 = 2.0*v2-1.0
rsq = v1**2 + v2**2
if (rsq > 0.0 .and. rsq < 1.0) exit
enddo
rsq = sqrt(-2.0*log(rsq)/rsq)
harvest = v1*rsq
g = v2*rsq
gauss_stored = .true.
endif
end function gauss_dev
! also other subroutines that calls gauss_dev()
end module moves
Однако, когда я компилирую код, я получаю сообщение об ошибке:
error #6451: A dummy argument name is required in this context. [SEEDVAL]
type (mod_seed), intent(inout) :: seedval
Я не уверен, что вызвало ошибку. Но так как я случайно пытался использовать опции intent()
, я случайно обнаружил, что без указания intent()
код компилируется без ошибок, что странно, потому что я думал, что без указания intent()
компилятор фортранта принимает inout
в качестве опция по умолчанию? Но в результате НЕ указания intent()
симуляция застревает в цикле do:
do
v1 = genrand_real(seedval%seedvalue)
v2 = genrand_real(seedval%seedvalue)
v1 = 2.0*v1-1.0
v2 = 2.0*v2-1.0
rsq = v1**2 + v2**2
if (rsq > 0.0 .and. rsq < 1.0) exit
enddo
потому что seedval%seedvalue
возвращает 0, что вызывает rsq
постоянно сбойное if (rsq > 0.0 .and. rsq < 1.0) exit
условие.
Перед публикацией этой темы я прочитал намерение Fortran (inout) вместо пропущенного намерения , я вижу потенциальную проблему совместимости, но она появилась с Fortran 2003 в соответствии с темой.
Подводя итог, я задаю два вопроса: 1. Есть ли разница между указанием intent(inout)
и отсутствием указания на фортране 90?
2. Что касается сообщения об ошибке при указании intent(inout)
, в чем причина?
Любая подсказка будет оценена!