ошибка # 6451: в этом контексте требуется фиктивное имя аргумента - PullRequest
0 голосов
/ 03 июля 2018

Я получаю странную ошибку при компиляции своего кода симуляции, написанного на Фортране 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), в чем причина?

Любая подсказка будет оценена!

1 Ответ

0 голосов
/ 03 июля 2018
  1. В Фортране 90, есть ли разница между указанием намерения (inout) и не указанием вообще?

Да: уже в стандарте Fortran 90, фиктивный аргумент с intent(inout) должен был быть определим, и это не было требованием для фиктивных аргументов без атрибута намерения, см. Раздел 5.1.2.3 стандарта Fortran 90.

Перед публикацией этой темы я прочитал намерение Fortran (inout) вместо пропущенного намерения , я вижу потенциальную проблему совместимости, но она появилась с Fortran 2003 в соответствии с темой.

Пожалуйста, прочитайте эту ветку более внимательно, пока они обсуждают проблему со ссылками на Фортран 2003, ни в коем случае не говорят ничего об этом, представленном в версии стандарта 2003 года.

  1. Что касается сообщения об ошибке при указании намерения (inout), в чем причина?

Когда вы не указали intent из seedval и не указали seedval в качестве фиктивного аргумента функции, компилятор подумал, что seedval является локальной переменной, и был ей доволен. В тот момент, когда вы определили intent для seedval, не указав его в качестве фиктивной переменной, компилятор, естественно, был недоволен (intent может быть предоставлено только для фиктивных аргументов), поэтому возникла ошибка.

с / без указания намерения (inout), код возвращает разные результаты, какая-либо подсказка?

Может быть, мне не хватает этого, но не могли бы вы уточнить, где вы инициализируете seedval%seedvalue? Если вы используете неинициализированную переменную, это легко объяснит, почему разные компиляции дают разные значения.


Если я правильно следую вашему описанию проблемы (пожалуйста, исправьте меня иначе), ваш код запускался только тогда, когда (а) seedval не был указан в качестве фиктивного аргумента function gauss_dev, и у него не было intent атрибут; или (b) seedval был указан как фиктивный аргумент функции и имел intent(inout).

В коде (a) и (b) поведение было совсем другим, потому что в (b) компонент seedval%seedvalue был надлежащим образом инициализирован вашей подпрограммой read_iseed, в то время как в (a) seedval была переменной локально по gauss_dev, которое использовалось genrand_real до инициализации. В этом случае компилятор, вероятно, инициализировал seedval%seedvalue в ноль в gauss_dev, а ваша функция genrand_real возвращает нули (как для ir, так и genrand_real), когда переменная ir равна нулю на входе, следовательно, бесконечный цикл, который вы описали.

Обратите внимание, что несколько запусков двоичного кода, скомпилированного после (b), скорее всего, приведут к разным числовым результатам, поскольку системный вызов, который вы делаете в read_iseed

od -vAn -N4 -td4 < /dev/urandom

обычно возвращает различные целочисленные значения для вашего семени.

...