我想为不同的参数多次求解微分方程。它比这更复杂,但为了清楚起见,我们说ODE为y'(x) = (y+a)*x
y(0) = 0
,我想要y(1)
。我从netlib中选择了dverk算法来解决ODE,并且它希望右侧的函数具有某种形式。现在我对英特尔Fortran编译器的处理如下(简化):
subroutine f(x,a,ans)
implicite none
double precision f,a,ans,y,tol,c(24),w(9)
...
call dverk(1,faux,x,y,1.d0,tol,ind,c,1,w)
...
contains
subroutine faux(n,xx,yy,yprime)
implicite none
integer n
double precision xx,yy(n),yprime(n)
yprime(1) = (yy(1)+a)*xx
end subroutine faux
end subroutine f
这对ifort工作得很好,子子程序faux
看到参数a
,一切都按预期工作。但我希望代码与gfortran兼容,并且使用此编译器,我收到以下错误消息:
错误:内部程序'faux'不允许作为(1)
的实际参数
我需要在faux
内设置f
例程,否则我不知道如何告诉它a
的值,因为我无法更改列表参数,因为这是dverk
例程所期望的。
我想保留dverk
例程并了解如何在没有解决方法的情况下解决这个特定问题,因为当我需要将参数化函数与不同的集成器集成时,我觉得它会再次变得重要。
答案 0 :(得分:5)
您可以将此全部放在模块中,并使a
成为全局模块变量。使faux
成为一个模块程序。这样,它就可以访问a
。
module ode_module
double precision::a
contains
subroutine f(x,a,ans)
implicit none
double precision f,ans,y,tol,c(24),w(9)
call dverk(1,faux,x,y,1.d0,tol,ind,c,1,w)
end subroutine
subroutine faux(n,xx,yy,yprime)
implicite none
integer n
double precision xx,yy(n),yprime(n)
yprime(1) = (yy(1)+a)*xx
end subroutine faux
end module
答案 1 :(得分:3)
您可以在此处查看哪些编译器支持此F2008功能:
http://fortranwiki.org/fortran/show/Fortran+2008+status
在该页面上,搜索“内部程序作为实际参数”。
答案 2 :(得分:0)
Fortran 2008允许传递内部过程。它不仅限于模块。您只需要确保包含过程仍在运行。无法保存指针并使LISP和许多现代语言都知道所谓的“闭包”。在Fortran或C等语言中,未保存未来调用的封闭环境,并且指向内部函数的指针无效。
内部程序优于模块程序的优点是您可以共享数据而无需在整个模块中共享数据。
GCC(gfortran),英特尔Fortran和Cray Fortran(个人测试)以及其他可能的合理旧版本都可以使用。我记得PGI和Oracle Fortran无法编译。如Daniel所示,可以在http://fortranwiki.org/fortran/show/Fortran+2008+status(搜索内部过程作为实际参数)进行检查。该表的最新版本定期发布在ACM SIGPLAN Fortran论坛。
本文http://software.intel.com/en-us/blogs/2009/09/02/doctor-fortran-in-think-thank-thunk/
中有一些有趣的信息