Python 在带有F2PY的numpy数组上使用Fortran函数时,结果不一致
我试图了解F2PY是如何工作的。为此,我编写了一个简单的Fortran函数,该函数将数组作为输入,并返回数组元素的总和 我编写了相同函数的三个不同版本,我希望它们具有相同的结果:Python 在带有F2PY的numpy数组上使用Fortran函数时,结果不一致,python,numpy,fortran,f2py,Python,Numpy,Fortran,F2py,我试图了解F2PY是如何工作的。为此,我编写了一个简单的Fortran函数,该函数将数组作为输入,并返回数组元素的总和 我编写了相同函数的三个不同版本,我希望它们具有相同的结果: function rsum(arr) real, dimension(:), intent(in) :: arr real :: rsum rsum=sum(arr) end function rsum function rsum1(arr) real(8), dimension(:), intent(in) ::
function rsum(arr)
real, dimension(:), intent(in) :: arr
real :: rsum
rsum=sum(arr)
end function rsum
function rsum1(arr)
real(8), dimension(:), intent(in) :: arr
real(8) :: rsum1
rsum1=sum(arr)
end function rsum1
function rsum2(arr) result(s)
real, dimension(:), intent(in) :: arr
real :: s
s=sum(arr)
end function rsum2
function rsum3(arr) result(s)
real(8), dimension(:), intent(in) :: arr
real(8) :: s
s=sum(arr)
end function rsum3
测试这些函数的python脚本如下所示:
from numpy import *
import ftest as f
a=array(range(3))
print(f.rsum(a))
print(f.rsum1(a))
print(f.rsum2(a))
print(f.rsum3(a))
但结果是:
3.0
0.0
3.0
3.0
除了rsum1
中的0.0
之外,所有结果都是正确的。我发现更奇怪的是,rsum3
,我只需更改函数结果的名称(或者,至少,我认为我正在这样做),就可以完美地工作
我知道这与Fortran和numpy之间的类型转换有关,但我不明白问题是什么
PS:我最近才学会Fortran。简短回答和解决方法
问题的根本原因与在函数中使用假定的形状伪参数(即arr
)有关。Fortran要求此类函数具有显式接口@VladimirF对您的(相关?)问题给出了极好的回答,表明首选解决方案是将函数放在模块中。假设您的函数代码列表保存在名为funcs.f90
的文件中,您只需将它们放入一个名为mod_funcs.f90
的模块中,如下所示:
module mod_funcs
implicit none
contains
include "funcs.f90"
end module mod_funcs
用F2PYpython-m numpy.F2PY-m ftest-c mod_funcs.f90
将python测试脚本中的import语句更新为from ftest import mod_funcs as f
,然后运行它以获得预期结果:
3.0
3.0
3.0
3.0
较长的答案和解释
Fortran函数
s被F2PY包装在子例程
s中。为了以符合Fortran标准的方式支持假定形状数组,F2PY创建的子例程包装包含用户定义的具有假定形状伪参数的函数的接口
s。使用F2PY包装时,您可以通过指定带有--build dir
标志的生成目录来查看这些包装,例如:
python -m numpy.f2py --build-dir .\build -m ftest -c funcs.f90
查看为有问题的函数rsum1
创建的包装器很有启发性(我正在从ftest-f2pywrappers.f
中逐字复制F2PY的缩进):
请注意,由于,rsum1的接口
意味着数据类型为real
的函数,不是预期的real(8)
,因此接口中存在数据类型不匹配!这解释了为什么带有显式result
语句(rsum3
)的看似相同的函数返回正确的结果。在原始示例中,其结果具有正确的数据类型。幸运的是,rsum
具有正确的接口。如果将rsum
的名称更改为例如isum
,则其F2PY子例程包装器接口中的隐式数据键入规则将意味着它有一个integer
结果,并且您将从(修改以反映名称从fsum
更改为isum
)python脚本中获得以下输出:
0.0
0.0
3.0
3.0
因此,在我看来,F2PY为具有假定形状伪参数的函数创建接口的方式似乎存在缺陷(可以通过将这些函数直接放入模块中,或者通过使用result
显式声明函数的返回值来绕过)
为了完整起见,我使用的是
python3.6.3::Intel Corporation
,以及NumPy 1.14.3
,以及GNU-Fortran(GCC)8.2.0
,如果你是新手,不要学习real(8)
的坏习惯,人们从哪里学来的?它不在任何好的教科书中。rsum1
和rsum3
应该完全相同。但也许f2py解释了一个错误,我可以复制它。当我在从f2py调用的Fortran子例程中调用它们时,结果是正确的。但即使在Python中,报告的f.*
函数的签名也是正确的。@VladimirF关于表示法real(8),有人教过我。为什么这么糟糕?另外,我不明白:在运行脚本时,您是否遇到了与我相同的错误?是的,我遇到了相同的错误。Real(8)是不可移植的,它不能用某些编译器编译。看到和
0.0
0.0
3.0
3.0