错误 #6451:在此上下文中需要虚拟参数名称

error #6451: A dummy argument name is required in this context

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

在说出问题之前,这是我所拥有的可以正常工作的东西: module prng 下面是一个伪随机数生成器(它在 fortran 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

为了使用seedvalue,需要先声明type(mod_seed) :: seedval,然后genrand_real(seedval%seedvalue) returns (0,1)中的一个真实值。

到目前为止上面提到的都工作正常!下面是我要实现的,基本上我采用了高斯偏差函数,function gauss_dev() result(harvest),来自 Fortran 中的数值食谱(第 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

由于 seedvalueprng 中被重新分配,凭直觉我会使用 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-loop 中:

       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 returns 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. In fortran 90, is there a difference between specifying intent(inout) and not specifying at all?

是:在 Fort运行 90 标准中,需要定义带有 intent(inout) 的虚拟参数,这不是没有 intent 属性的虚拟参数的要求,请参阅第 5.1 节.2.3 堡运行 90 标准。

Before posting this thread, I read Fortran intent(inout) versus omitting intent, I see the potential compatibility issue out there, but that's introduced since Fortran 2003 according to the thread.

请更仔细地阅读该主题,虽然他们确实引用了 Fort运行 2003 参考资料来讨论这个问题,但他们从未对 2003 版标准中引入的内容发表任何评论。

  1. In regard to the error message when specifying intent(inout), what's the cause of it?

当您没有指定 seedvalintent 并且您没有将 seedval 列为函数的伪参数时,编译器认为 seedval是一个局部变量并且对此很满意。当你为 seedval 定义了一个 intent 而没有将其列为虚拟变量时,编译器自然不高兴(intent 只能为虚拟参数提供),因此它引发了错误.

with/without having intent(inout) specified, code returns different results, any clue?

也许我遗漏了它,但你能澄清一下你在哪里初始化 seedval%seedvalue 吗?如果您使用的是未初始化的变量,这很容易解释为什么不同的编译会产生不同的值。


如果我正确地遵循了您对问题的描述(否则请更正我),您的代码仅 运行 当 (a) seedval 未被列为 [=21 的虚拟参数时=],并且它没有 intent 属性;或 (b) seedval 被列为函数的伪参数并且它具有 intent(inout).

代码在 (a) 和 (b) 中的行为非常不同,因为在 (b) 中,组件 seedval%seedvalue 已由您的 read_iseed 子例程适当地初始化,而在 (a) seedvalgauss_dev 的局部变量,在初始化之前被 genrand_real 使用。在这种情况下,编译器可能在 gauss_dev 中将 seedval%seedvalue 初始化为零,而你的 genrand_real 函数 return 为零(对于 irgenrand_real) 当变量 ir 在输入处为零时,因此出现您描述的无限循环。

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

中进行的系统调用
od -vAn -N4 -td4 < /dev/urandom

您的种子通常 return 不同的整数值。