从Fortran模块中定义的函数打印到标准输出
我正在努力学习Fortran(不幸的是,这是我的研究小组的一项必要任务)——我给自己设定的任务之一是将数字配方书中的一个必要函数(相关的勒让德多项式)打包成符合Fortran 03的模块。原始程序(f77)具有以下形式的一些错误处理:从Fortran模块中定义的函数打印到标准输出,fortran,Fortran,我正在努力学习Fortran(不幸的是,这是我的研究小组的一项必要任务)——我给自己设定的任务之一是将数字配方书中的一个必要函数(相关的勒让德多项式)打包成符合Fortran 03的模块。原始程序(f77)具有以下形式的一些错误处理: if(m.lt.0.or.m.gt.1.or.abs(x).gt.1)pause 'bad arguments in plgndr' 自f77以来,Pause似乎已被弃用,因为使用此行会导致编译错误,因此我尝试了以下方法: module sha_helper
if(m.lt.0.or.m.gt.1.or.abs(x).gt.1)pause 'bad arguments in plgndr'
自f77以来,Pause似乎已被弃用,因为使用此行会导致编译错误,因此我尝试了以下方法:
module sha_helper
implicit none
public :: plgndr, factorial!, ylm
contains
! numerical recipes Associated Legendre Polynomials rewritten for f03
function plgndr(l,m,x) result(res_plgndr)
integer, intent(in) :: l, m
real, intent(in) :: x
real :: res_plgndr, fact, pll, pmm, pmmp1, somx2
integer :: i,ll
if (m.lt.0.or.m.gt.l.or.abs(x).gt.1) then
write (*, *) "bad arguments to plgndr, aborting", m, x
res_plgndr=-10e6 !return a ridiculous value
else
pmm = 1.
if (m.gt.0) then
somx2 = sqrt((1.-x)*(1.+x))
fact = 1.
do i = 1, m
pmm = -pmm*fact*somx2
fact = fact+2
end do
end if
if (l.eq.m) then
res_plgndr = pmm
else
pmmp1 = x*(2*m+1)*pmm
if(l.eq.m+1) then
res_plgndr = pmmp1
else
do ll = m+2, l
pll = (x*(2*ll-1)*pmmp1-(ll+m-1)*pmm)/(ll-m)
pmm = pmmp1
pmmp1 = pll
end do
res_plgndr = pll
end if
end if
end if
end function plgndr
recursive function factorial(n) result(factorial_result)
integer, intent(in) :: n
integer, parameter :: RegInt_K = selected_int_kind(20) !should be enough for the factorials I am using
integer (kind = RegInt_K) :: factorial_result
if (n <= 0) then
factorial_result = 1
else
factorial_result = n * factorial(n-1)
end if
end function factorial
! function ylm(l,m,theta,phi) result(res_ylm)
! integer, intent(in) :: l, m
! real, intent(in) :: theta, phi
! real :: res_ylm, front_block
! real, parameter :: pi = 3.1415926536
! front_block = sqrt((2*l+1)*factorial(l-abs(m))/(4*pi*))
! end function ylm
end module sha_helper
尝试:
您的程序执行所谓的递归IO-对
plgndr
的初始调用位于IO语句(打印语句)[将输出定向到控制台]的输出项列表中-在该函数中,您还尝试执行另一个IO语句[输出到控制台]。这是不允许的-参见F2003的9.11p2和p3或F2008的9.12p2
解决方案是将函数调用与主程序中的io语句分离,即
REAL :: a_temporary
...
a_temporary = plgndr(1,2,0.1)
PRINT *, a_temporary
F2008中的其他替代方案(但不是F2003-因此第一段中的[]部分)包括将函数的输出定向到不同的逻辑单元(注意,WRITE(*、…
和PRINT…
引用相同的单元)
在F2008中,您还可以将WRITE语句替换为带有消息的STOP语句(消息必须是常量,这样您就不会报告有问题的值)
某些编程风格不鼓励在函数中执行IO的部分原因是可能会无意中调用递归IO。请编辑您的问题,以包含完整的代码。所包含的程序片段中显然没有错误。因此,这可能是由于程序的其他部分中的某些内容造成的。谢谢--在这种情况下,NE是为了避免函数中的IO,在主代码中有一种错误检查的好方法吗?我猜你可以在函数的范围之外选择一个返回值并检查它。h一个单独的错误标志参数或类似参数。如果它仍然是一个函数(即,我希望它在更复杂的表达式中作为主函数引用),那么我也希望我的函数是纯函数-这目前排除了使用[error]STOP或doing IO(尽管在未来的标准中可能会取消对错误停止的限制)。如果支持,则使用
IEEE\u值(x,IEEE\u QUIET\u NAN)
作为良好的“无效”值,因为在随后使用时,该值会敏感地传播。
if (m.lt.0.or.m.gt.l.or.abs(x).gt.1) then
write (*, *) "bad arguments to plgndr, aborting", m, x
stop
else
...
end if
REAL :: a_temporary
...
a_temporary = plgndr(1,2,0.1)
PRINT *, a_temporary