ОК, чтобы увеличить ответ от @ Jerry101, я написал модифицированный код. Здесь ключевая проблема заключается в том, что IMAXINV
явно не объявлен как REAL
, поэтому он интерпретируется как INTEGER
(в результате IMAXINV = 1.0/IMAX
всегда будет 0 в исходном коде). Кроме того, я удалил ISEED
из блока COMMON
(потому что он передан как аргумент) и поместил еще один оператор COMMON
в RANDU
для обмена переменными среди подпрограмм. С этими изменениями программа работает правильно.
PROGRAM RANDOM
COMMON RANDOMNUMBER !<--- ISEED is deleted from here
ISEED = 123
J=1
7 CALL RANDU(ISEED)
J=J+1
WRITE(*,*) RANDOMNUMBER !<--- write to STDOUT for test
IF (J < 100) GOTO 7
END
SUBROUTINE RANDU(ISEED)
real IMAXINV !<--- this is necessary
COMMON RANDOMNUMBER !<--- this is also necessary to share variables
PARAMETER (IMAX = 2147483647, IMAXINV = 1./IMAX)
ISEED = ISEED * 65539
IF(ISEED<0) ISEED = ISEED + IMAX + 1
RANDOMNUMBER = ISEED * IMAXINV
END
Как было предложено в другой ответ, мы могли бы также использовать FUNCTION
вернуть переменную непосредственно. Тогда нам не нужно использовать COMMON
, поэтому код становится немного чище.
PROGRAM RANDOM
ISEED = 123
J=1
7 RANDOMNUMBER = RANDU(ISEED)
J=J+1
WRITE(*,*) RANDOMNUMBER
IF (J < 100) GOTO 7
END
FUNCTION RANDU(ISEED)
real IMAXINV
PARAMETER (IMAX = 2147483647, IMAXINV = 1./IMAX)
ISEED = ISEED * 65539
IF(ISEED<0) ISEED = ISEED + IMAX + 1
RANDU = ISEED * IMAXINV !<--- "RANDU" is the return variable
END
Но обратите внимание, что, когда FUNCTION
используется, тип переменного возврата должен быть явно объявлен в вызывающей программе, если имя функции не соответствует неявному правилу. (В приведенном выше коде RANDU
не объявляется явно, поскольку он интерпретируется как REAL
). Так или иначе, есть много предостережений в неявном правиле ввода в Fortran77 ...
Дополнительные примечания:
Чтобы избежать этих ошибок, я предлагаю использовать Fortran> = 90 (а не Fortran77), поскольку он предоставляет множество возможностей для предотвращения таких ошибок. Например, минимально модифицированный код может выглядеть следующим образом:
module mymodule
contains
subroutine randu (istate, ran)
implicit none
integer, parameter :: IMAX = 2147483647
real, parameter :: IMAXINV = 1.0/IMAX
integer, intent(inout) :: istate
real, intent(out) :: ran
istate = istate * 65539
if (istate < 0) istate = istate + IMAX + 1
ran = istate * IMAXINV
end subroutine
end module
program main
use mymodule, only: randu
implicit none
integer :: j, istate
real :: randomnumber
istate = 123 !! seed for RANDU()
do j = 1, 99
call randu (istate, randomnumber)
write(*,*) randomnumber
enddo
end program
Здесь
implicit none
используется для обеспечения соблюдения декларации всех переменных в явном виде. Это полезно, чтобы избежать неправильного ввода переменных (например, IMAXINV
в вопрос!).
- Подпрограмма
RANDU
содержится в module
, так что компилятор предоставляет явный интерфейс и много полезных проверок (короче говоря, module
- это нечто вроде пространства имен на C++). module
также может использоваться для определения глобальных переменных в гораздо более безопасном, чем COMMON
.
- Я использовал
do
... enddo
конструкцию для зацикливания над j
вместо того, чтобы увеличивать ее вручную и используя goto
. Первое на самом деле проще в использовании, а также goto
имеет тенденцию делать код часто менее читаемым ...
- Я назвал файл программы как «test.f90» (обратите внимание на суффикс .f90), который позволяет свободно форматировать. Кроме того, для переменных полезно использовать строчные буквы.
- [Кроме того, поскольку
iseed
хранит информацию о текущем состоянии генератора случайных чисел (псевдо), может быть лучше использовать какое-то другое имя переменной (например, istate и т. Д.), Чтобы напомнить, что его значение необходимо сохранить во время вызовов .]
Так что, если вы заинтересованы, пожалуйста, рассмотрите возможность использования более современную версию Fortran (а не Fortran77), что позволяет нам писать более безопасные и надежные коды :)
Используйте основной Фортран тег, чтобы сделать ваш пост более заметен. Существует множество высококачественных генераторов случайных чисел в Fortran. Fortran 90 даже имеет собственный собственный (неуказанное качество). Кроме того, отладка в этом веке проще. Фортран и область действия, безусловно, важная концепция в Fortran. –