Recursion `错误:Fortran 95中函数`的返回类型不匹配
我决定尝试在Fortran 95中实现阶乘函数(f2py限制),但我的努力只产生了两个返回类型不匹配错误Recursion `错误:Fortran 95中函数`的返回类型不匹配,recursion,functional-programming,fortran,gfortran,fortran95,Recursion,Functional Programming,Fortran,Gfortran,Fortran95,我决定尝试在Fortran 95中实现阶乘函数(f2py限制),但我的努力只产生了两个返回类型不匹配错误 解决方案的灵感 在Haskell,我们可以做一些类似的事情 fac\u助手n acc= 如果n您向我们显示的错误可能与调用factorial()的方式有关,而不是在此代码中。如果我将代码包装在以下示例中: program test implicit none integer :: i do i=1,10 write (*,'(i2,"! = ",i8)') i, fac
解决方案的灵感 在Haskell,我们可以做一些类似的事情
fac\u助手n acc=
如果n您向我们显示的错误可能与调用factorial()
的方式有关,而不是在此代码中。如果我将代码包装在以下示例中:
program test
implicit none
integer :: i
do i=1,10
write (*,'(i2,"! = ",i8)') i, factorial(i)
end do
contains
[cut and paste the code from your question]
end program
并使用gfortran 4.8.3进行编译:
gfortran -std=f95 -o fac fac.f90
我得到输出:
1! = 1
2! = 2
3! = 6
4! = 24
5! = 120
6! = 720
7! = 5040
8! = 40320
9! = 362880
10! = 3628800
确保使用正确的参数类型调用factorial()
,如果它不在模块或内部过程中,请使用显式接口。我注意到您没有在代码中使用implicit none
,因此还要验证您是否显式声明了调用factorial
的变量,以确保使用了正确的类型
如果您将这些过程用作外部过程(例如,不在主程序中或包含在模块中),则为了让调用过程知道预期结果,应使用显式接口。请参见下面的示例
program test
implicit none
integer :: i
interface
function factorial(n)
integer, intent(in) :: n
integer :: factorial
end function factorial
end interface
do i=1,10
write (*,'(i2,"! = ",i8)') i, factorial(i)
end do
end program
recursive function facHelper(n, acc) result(returner)
implicit none
integer, intent(in) :: n, acc
integer :: returner
if (n <= 1) then
returner = acc
else
returner = facHelper(n - 1, n * acc)
endif
end function facHelper
function factorial(n)
implicit none
integer, intent(in) :: n
integer :: factorial
interface
function facHelper(n,acc)
integer, intent(in) :: n, acc
integer :: facHelper
end function
end interface
factorial = facHelper(n, 1)
end function factorial
在本例中,factorial
位于模块中,fachhelper
位于模块中,但不可在外部调用(声明为私有且对主程序隐藏)。您将看到,这里的算法与建议的代码几乎相同,唯一的区别是添加了隐式none
。在主程序中,行use fact
让程序知道函数的接口 问题与解决方案
在对诸如隐式无等问题大惊小怪之后,似乎问题实际上在阶乘函数中
即使facHelper已定义为
recursive integer function facHelper(n, acc) result(returner)
如果factorial函数是在fachhelper之后定义的,factorial仍然不知道fachhelper返回一个整数
然后,解决方案是在阶乘函数中添加一行,告诉它fachhelper是整数:
function factorial(n)
integer::n
integer::factorial
integer::facHelper ! <-- Missing information now available
factorial = facHelper(n, 1)
end function factorial
多余的复活节彩蛋
将f2py v2与NumPy v1.8.0一起使用
虽然上述两个版本的fac.f95都将使用gfortran编译,但第二个版本将使f2py认为来自fachhelper的返回程序是真实的。但是,f2py确实正确处理了fac.f95的第一个版本
我想在Fortran中对尾部递归阶乘进行基准测试。我添加了阶乘的非尾部递归版本(名为vanillaFac)。整数大小也增加到种类=8
fac.f95现在包含
recursive function tailFacHelper(n, acc) result(returner)
integer (kind=8)::n
integer (kind=8)::acc
integer (kind=8)::returner
if (n <= 1) then
returner = acc
else
returner = tailFacHelper(n - 1, n * acc)
endif
end function tailFacHelper
function tailFac(n)
integer (kind=8)::n
integer (kind=8)::tailFac
integer (kind=8)::tailFacHelper
tailFac = tailFacHelper(n, 1_8)
end function tailFac
recursive function vanillaFac(n) result(returner)
integer (kind=8)::n
integer (kind=8)::returner
if (n <= 1) then
returner = 1
else
returner = n * vanillaFac(n - 1)
endif
end function vanillaFac
我写了一个python脚本timer.py
导入liboptfac
导入libnooptfac
导入时间信息
def py_vanilla_fac(n):
如果n如何调用factorial
?我在接下来的几个小时内没有代表回答我自己的问题,但问题实际上是在factorial函数中,不知道fachhelper是整数。一旦我得到允许,我会发布我的答案。你没有发布你自己的答案,凯西的答案很好地展示了正确的用法。他甚至提到了隐式无的问题。@Vladimir F你能为我详细说明一下隐式无的位置吗,这样我尝试的解决方案就可以像现在写的那样工作?如果casey真的在逐字使用我尝试的解决方案,那么他唯一会使用隐式none的地方就是在他的程序测试中。重点是将您的程序放在模块或主程序中。然后,它们之间就有了明确的接口。隐式none只是帮助您更早地看到代码中的问题。你可以把它放在两个函数中。只将fachhelper
声明为整数是处理外部过程的一种相当古老的方式。声明显式接口或将过程放在模块中更有意义。显式接口的好处是编译器可以检查参数类型,而不仅仅是返回类型。这是一种非常不幸的修复方法。当您有更高级的参数类型并且它不提供任何错误检查时,它将失败。使用模块或将其内部化要好得多。对于f2py来说,模块方法是一条路。@Vladmir错误检查与实现阶乘的演示请求无关。Haskell示例不执行错误检查,对于问题的意图和目的完全有效。也不执行任何错误检查。@casey通过将facHelper声明为整数,您是指“递归整数函数facHelper”,还是指阶乘内部的“integer::facHelper”?如果您可以根据底线问题“Fortran95中的尾部递归阶乘实现看起来如何?”修改您的答案,以包含一个完整的示例,我会更倾向于接受您的答案。我尝试的解决方案和Haskell实现只是作为激发底线问题答案的素材:“尾部递归阶乘实现在Fortran95中会是什么样子?”如果您可以修改您的答案来解决这个问题,我会更倾向于接受您的答案。如果上面不清楚,您在问题中建议的解决方案是它的外观(请注意,我复制并粘贴到我的示例中,根本没有修改它)。您的问题不在于实现尾部递归,而是与通用Fortran问题有关,接口规范与您的算法无关。这对我来说没有意义。问题中建议的解决方案没有说明“integer::facHelper”“在阶乘函数中,我甚至无法编译,直到它这么说。@user0xf00查看我的编辑。如果仍然不清楚,请告诉我。@user0xf00我还为您添加了一个模块示例。
module fact
private :: facHelper
contains
recursive function facHelper(n, acc) result(returner)
implicit none
integer, intent(in) :: n, acc
integer :: returner
if (n <= 1) then
returner = acc
else
returner = facHelper(n - 1, n * acc)
endif
end function facHelper
function factorial(n)
implicit none
integer, intent(in) :: n
integer :: factorial
factorial = facHelper(n, 1)
end function factorial
end module fact
program test
use fact
implicit none
integer :: i
do i=1,10
write (*,'(i2,"! = ",i8)') i, factorial(i)
end do
end program
recursive integer function facHelper(n, acc) result(returner)
function factorial(n)
integer::n
integer::factorial
integer::facHelper ! <-- Missing information now available
factorial = facHelper(n, 1)
end function factorial
recursive function facHelper(n, acc) result(returner)
integer::n
integer::acc
integer::returner
if (n <= 1) then
returner = acc
else
returner = facHelper(n - 1, n * acc)
endif
end function facHelper
function factorial(n)
integer::n
integer::factorial
integer::facHelper
factorial = facHelper(n, 1)
end function factorial
recursive integer function facHelper(n, acc) result(returner)
integer::n
integer::acc
if (n <= 1) then
returner = acc
else
returner = facHelper(n - 1, n * acc)
endif
end function facHelper
integer function factorial(n)
integer::n
integer::facHelper
factorial = facHelper(n, 1)
end function factorial
gfortran --std=f95 -c ./fac.f95
recursive function tailFacHelper(n, acc) result(returner)
integer (kind=8)::n
integer (kind=8)::acc
integer (kind=8)::returner
if (n <= 1) then
returner = acc
else
returner = tailFacHelper(n - 1, n * acc)
endif
end function tailFacHelper
function tailFac(n)
integer (kind=8)::n
integer (kind=8)::tailFac
integer (kind=8)::tailFacHelper
tailFac = tailFacHelper(n, 1_8)
end function tailFac
recursive function vanillaFac(n) result(returner)
integer (kind=8)::n
integer (kind=8)::returner
if (n <= 1) then
returner = 1
else
returner = n * vanillaFac(n - 1)
endif
end function vanillaFac
f2py --overwrite-signature --no-lower fac.f95 -m liboptfac -h fac.pyf;
f2py -c --f90flags=--std=f95 --opt=-O3 fac.pyf fac.f95;
f2py --overwrite-signature --no-lower fac.f95 -m libnooptfac -h fac.pyf;
f2py -c --f90flags=--std=f95 --noopt fac.pyf fac.f95;
python timer.py
*****Fortran (optimizations level 03 enabled)*****
liboptfac.vanillaFac(20)
1000000 calls
Best of ten: 0.813575983047
liboptfac.tailFac(20)
1000000 calls
Best of ten: 0.843787193298
liboptfac.tailFacHelper(20, 1)
1000000 calls
Best of ten: 0.858899831772
*****Fortran (no optimizations enabled)*****
libnooptfac.vanillaFac(20)
1000000 calls
Best of ten: 1.00723600388
libnooptfac.tailFac(20)
1000000 calls
Best of ten: 0.975327014923
libnooptfac.tailFacHelper(20, 1)
1000000 calls
Best of ten: 0.982407093048
*****Python*****
py_vanilla_fac(20)
1000000 calls
Best of ten: 6.47849297523
py_tail_fac(20)
1000000 calls
Best of ten: 6.93045401573
py_tail_fac_helper(20, 1)
1000000 calls
Best of ten: 6.81205391884