fortran - 错误 #6451:在此上下文中需要一个虚拟参数名称
问题描述
在编译用 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)
在(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
必须在调用之前声明!
由于在 中seedvalue
重新分配prng
,直觉上我会使用intent(inout)
option. 这是我的解决方法:
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
返回 0,这会导致rsq
不断失败的if (rsq > 0.0 .and. rsq < 1.0) exit
情况。
在发布此线程之前,我阅读了Fortran intent(inout) 与 omitting intent,我看到了潜在的兼容性问题,但根据线程,这是自 Fortran 2003 以来引入的。
intent(inout)
到最后我有两个问题:1.在fortran 90中,指定和不指定有区别吗?2. 关于指定时的错误信息intent(inout)
,是什么原因造成的?
任何提示将不胜感激!
解决方案
- 在 fortran 90 中,指定意图(输入输出)和根本不指定之间有区别吗?
是的:已经在 Fortran 90 标准中,intent(inout)
需要定义一个虚拟参数,这不是没有意图属性的虚拟参数的要求,请参阅 Fortran 90 标准的第 5.1.2.3 节。
在发布此线程之前,我阅读了Fortran intent(inout) 与 omitting intent,我看到了潜在的兼容性问题,但根据线程,这是自 Fortran 2003 以来引入的。
请更仔细地阅读该线程,虽然他们确实讨论了引用 Fortran 2003 参考的问题,但他们从未对 2003 版标准中引入的这个问题发表任何评论。
- 关于指定intent(inout)时的错误信息,是什么原因造成的?
当您没有指定intent
ofseedval
并且没有将seedval
其列为函数的虚拟参数时,编译器会认为这seedval
是一个局部变量并对此感到满意。intent
在您定义for的那一刻seedval
,没有将其列为虚拟变量,编译器自然不高兴(intent
只能为虚拟参数提供),因此引发了错误。
有/没有指定意图(inout),代码返回不同的结果,有什么线索吗?
也许我错过了它,但你能澄清一下你在哪里初始化seedval%seedvalue
吗?如果您使用的是未初始化的变量,那将很容易解释为什么不同的编译会产生不同的值。
如果我正确地遵循了您对问题的描述(否则请更正我),您的代码仅在 (a)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
通常会为您的种子返回不同的整数值。
推荐阅读
- r-markdown - 为什么 blogdown::hugo_build() 不能处理 Lua 过滤器?
- laravel - 如何从嵌套关系中获取特定列 - Laravel
- git - 如何根据我要克隆的 git 存储库来源自动更改我的本地 git config `user.email`?
- shell - 带变量的 curl 不起作用 - Shell 脚本
- linux - 尝试访问结构文件 private_data 时出错
- javascript - 如何在页面上的隐藏元素上使用 jQuery 添加类和删除类
- php - 更改 PHP 收到的 URL(通过 .htaccess?)
- css - CSS Wordpress 联系表格定制
- flutter - 如何实现交互式复杂形状?
- java - 在 UIDAI aadhaar pdf 中屏蔽 aadhaar 编号