错误#6451:在这种情况下,需要一个伪参数名称

时间:2018-07-03 11:09:56

标签: fortran fortran90 intel-fortran

编译我用Fortran 90编写的模拟代码时遇到一个奇怪的错误,我希望能有一些帮助。我正在使用ifort版本18.0.3。

在说明问题之前,这是我能正常工作的内容: module prng下面是一个伪随机数生成器(它在fortran 77中,但是我已经对其进行了测试,以防万一有兼容性问题,它可以正常工作!):<​​/ p>

  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)中的实值。

到目前为止,上述所有方法都工作正常!以下是我要实现的内容,基本上我采用了Fortran的数值配方(第280页)中的高斯偏差函数function gauss_dev() result(harvest),请参见下面的源代码:

 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(),fortran编译器是否将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 intent(inout) versus omitting intent,我看到了潜在的兼容性问题,但这是从Fortran 2003开始根据该线程引入的。

最后,我有两个问题:1.在fortran 90中,指定intent(inout)与根本不指定之间有区别吗? 2.关于指定intent(inout)时的错误消息,其原因是什么?

任何提示将不胜感激!

1 个答案:

答案 0 :(得分:4)

  
      
  1. 在fortran 90中,指定intent(inout)与根本不指定之间有区别吗?
  2.   

是:已经在Fortran 90标准中,需要定义带有intent(inout)的伪参数,并且这对没有intent属性的伪参数不是必需的,请参阅Fortran 90标准的5.1.2.3节

  

在发布此线程之前,我读过Fortran intent(inout) versus omitting intent,我看到了潜在的兼容性问题,但这是自Fortran 2003开始根据该线程引入的。

请认真阅读该线程,尽管他们确实引用Fortran 2003参考文献来讨论该问题,但他们丝毫没有说过在2003版标准中引入的任何内容。

  
      
  1. 关于指定intent(inout)时的错误消息,其原因是什么?
  2.   

当您未指定intent中的seedval并且没有将seedval列为该函数的伪参数时,编译器认为seedval是一个局部变量,对此感到满意。在为intent定义seedval而不将其列为虚拟变量的那一刻,编译器自然就感到不满意(intent仅可用于虚拟参数),因此引发了错误

  

有/没有指定intent(inout),代码返回不同的结果,有任何线索吗?

也许我错过了它,但是请您说明一下seedval%seedvalue的初始化位置吗?如果您使用的是未初始化的变量,则可以轻松解释为什么不同的编译产生不同的值。


如果我正确地按照您对问题的描述进行操作(请更正我),则只有当(a)seedval没有被列为function gauss_dev的伪参数时,您的代码才运行没有intent属性;或(b)seedval被列为该函数的伪参数,并且具有intent(inout)

代码在(a)和(b)中的行为截然不同,因为在(b)中,seedval%seedvalue子例程已适当地初始化了组件read_iseed,而在(a){{ 1}}是seedval局部变量,gauss_dev在初始化之前已使用过。在这种情况下,编译器可能在genrand_real中将seedval%seedvalue初始化为零,并且当变量gauss_devgenrand_real时,您的ir函数返回零。 genrand_real在输入时为零,因此您描述的是无限循环。

请注意,在(b)之后编译的二进制文件的多次运行很可能会产生不同的数值结果,因为您在ir内进行了系统调用

read_iseed

通常会为您的种子返回不同的整数值。