我很难理解Fortran接口。粘贴在问题末尾的测试代码代码在ifort< =版本15上编译得很好,但在版本16及更高版本上导致灾难性的编译器错误。在gfortran上相同(编译时出错)。但是,在g95上,编译以以下错误结束
In file test.f90:79
call rk4(y, dydx, x, h, yout1, der, pars,*10)
1
Error: Interface of actual procedure does not match interface of dummy procedure at (1)
In file test.f90:81
call rk4(y, dydx, x, h/2.d0, yout2, der, pars,*10)
1
Error: Interface of actual procedure does not match interface of dummy procedure at (1)
In file test.f90:85
call rk4(yout2, dydx2, x+h/2.d0, h/2.d0, yout2, der, pars,*10)
1
Error: Interface of actual procedure does not match interface of dummy procedure at (1)
但我不确定我做错了什么......
module RK
implicit none
contains
SUBROUTINE rk4(y, dydx, x, h, yout, der, pars, *)
IMPLICIT NONE
integer, parameter :: dp=kind(1.d0)
REAL(dp), DIMENSION(:), INTENT(IN) :: y,dydx,pars
REAL(dp), INTENT(IN) :: x,h
REAL(dp), DIMENSION(:), INTENT(OUT) :: yout
REAL(dp) :: h6,hh,xh
REAL(dp), DIMENSION(size(y)) :: dym,dyt,yt
INTERFACE
SUBROUTINE der(x,y,dydx,pars,*)
IMPLICIT NONE
integer, parameter :: dp=kind(1.d0)
REAL(dp), INTENT(IN) :: x
REAL(dp), DIMENSION(:), INTENT(IN) :: pars
REAL(dp), DIMENSION(:), INTENT(IN) :: y
REAL(dp), DIMENSION(:), INTENT(OUT) :: dydx
END SUBROUTINE der
END INTERFACE
hh = h*0.5d0
h6 = h/6.d0
xh = x + hh
yt(:)=y(:)+hh*dydx(:)
call der(xh, yt, dyt, pars,*10)
yt(:)=y(:)+hh*dyt(:)
call der(xh, yt, dym, pars,*10)
yt(:)=y(:)+h*dym(:)
dym(:)=dyt(:)+dym(:)
call der(x+h, yt, dyt, pars,*10)
yout(:)=y(:)+h6*(dydx(:)+dyt(:)+2.d0*dym(:))
return
10 return 1
end subroutine
subroutine adaptive_RK4(y,dydx,x,h,yout2,yerr,der,pars,*)
implicit none
integer, parameter :: dp=kind(1.d0)
REAL (dp) :: h, x
REAL (dp), DIMENSION (:) :: y, dydx, yout2, yerr, pars
REAL (dp), DIMENSION (size(y)) :: dydx2, yout1
intent(in) :: y, dydx, x, h, pars
intent(out) :: yout2, yerr
INTERFACE
SUBROUTINE der(x,y,dydx,pars,*)
IMPLICIT NONE
integer, parameter :: dp=kind(1.d0)
REAL(dp), INTENT(IN) :: x
REAL(dp), DIMENSION(:), INTENT(IN) :: pars
REAL(dp), DIMENSION(:), INTENT(IN) :: y
REAL(dp), DIMENSION(:), INTENT(OUT) :: dydx
END SUBROUTINE der
END INTERFACE
call rk4(y, dydx, x, h, yout1, der, pars,*10)
call rk4(y, dydx, x, h/2.d0, yout2, der, pars,*10)
call der(x+h/2.d0, yout2, dydx2, pars,*10)
call rk4(yout2, dydx2, x+h/2.d0, h/2.d0, yout2, der, pars,*10)
yerr(:)=yout2(:)-yout1(:)
yout2(:)=(16.d0*yout2(:)-yout1(:))/15.d0
return
10 return 1
end subroutine
end module
module derivative
implicit none
contains
SUBROUTINE derr(x,y,dydx,pars,*)
IMPLICIT NONE
integer, parameter :: dp=kind(1.d0)
REAL(dp), INTENT(IN) :: x
REAL(dp), DIMENSION(:), INTENT(IN) :: pars
REAL(dp), DIMENSION(:), INTENT(IN) :: y
REAL(dp), DIMENSION(:), INTENT(OUT) :: dydx
dydx=(pars+y)*x
return
END SUBROUTINE derr
end module
program test
use rk
use derivative
implicit none
integer, parameter :: dp=kind(1.d0)
real(dp), dimension(2) :: y,pars,dydx, yout, yerr
real(dp) :: x
y=(/0.1d0,2.d0/)
pars=(/0.7d0,3.d0/)
x=2.1d0
call derr(x,y,dydx,pars,*10)
write(*,*) dydx
call adaptive_RK4(y,dydx,x,0.0001d0,yout,yerr,derr,pars,*10)
stop
10 write(*,*) "some error"
end program
答案 0 :(得分:1)
代码在gfortran版本6和7中运行良好。
Gfortran版本4.8崩溃,但这是编译器的问题。即使代码不好,编译器也不应该崩溃。
同样适用于英特尔Fortran。如果在编译期间崩溃则是编译器的错误。
现在,代码实际上并不是很好,并且使用了编译器可能很难的功能。当涉及违反标准的事情时,gfortran 6抱怨:
interface2.f90:81:9:
call rk4(yout2, dydx2, x+h/2.d0, h/2.d0, yout2, der, pars,*10)
1
Warning: Same actual argument associated with INTENT(IN) argument ‘y’ and INTENT(OUT) argument ‘yout’ at (1)
Fortran不允许以这种方式将相同的变量传递给参数。编译器将假设intent(in)
参数永远不会更改,但在修改yout
时它会发生更改。这可能会导致严重的问题。
对于G95编译时错误,我认为编译器错误,错误消息是假的。 rk4
和adaptive_rk4
中的接口块完全相同。
我强烈建议您清理代码,摆脱备用退出功能,编译器编译代码会更容易。我预计这是由于您过度使用了未经过大量测试的备用返回功能。
对于您的下一个问题,请务必仔细阅读[mcve]。为了将来的问题,有必要使代码更短。这是您应该询问的实际MCVE,哪些可以作为错误报告的基础:
module m
implicit none
contains
subroutine a(d)
interface
subroutine d(*)
end subroutine d
end interface
10 return 1
end subroutine
subroutine b(d)
interface
subroutine d(*)
end subroutine d
end interface
call a(d)
end subroutine
end module
将它与你给我们的很长的代码进行比较。如果没有编译器崩溃消失(ifort 17和gcc 4.8),这不能再真正减少。问题显然在虚拟过程中(即使它实际上并未在任何地方调用),它使用备用返回功能,编译器无法正确处理它。
答案 1 :(得分:0)
我替换了DERR / DER实例的备用返回,然后编译工作在英特尔Fortran(XE 2017)。 我也同意(1)清理代码和(2)避免使用备用退货是明智的。