当我更改结果变量的名称时,为什么用f2py编译的Fortran函数返回零?
调用以下函数时,它会按预期返回当我更改结果变量的名称时,为什么用f2py编译的Fortran函数返回零?,fortran,f2py,Fortran,F2py,调用以下函数时,它会按预期返回1: integer function my_func() result(myresult) myresult = 1 end function my_func 但是当我修改返回值的名称以字母“r”开头时,函数返回0 integer function my_func() result(rresult) rresult = 1 end function my_func 这是什么原因造成的?我的第一个想法是它与隐式类型相关,但函数位于一个指定隐式无的
1
:
integer function my_func() result(myresult)
myresult = 1
end function my_func
但是当我修改返回值的名称以字母“r”开头时,函数返回0
integer function my_func() result(rresult)
rresult = 1
end function my_func
这是什么原因造成的?我的第一个想法是它与隐式类型相关,但函数位于一个指定隐式无
的模块中
这是完整的模块
module my_mod
implicit none
contains
integer function my_func() result(myresult)
myresult = 1
end function my_func
end module my_mod
我正在使用Fortran 90,并使用gfortran进行编译
编辑
下面是一个完整的程序来演示这个问题
生成文件:
.PHONY: pytest clean
CYTHON_LIB = fortran_mods.cpython-37m-x86_64-linux-gnu.so
FFLAGS += -fdefault-real-8
pytest: $(CYTHON_LIB)
./tests.py
$(CYTHON_LIB): my_mod.F90
f2py -c -m fortran_mods my_mod.F90 --f90flags="$(FFLAGS)"
clean:
rm *.so
my_mod.F90:
module my_mod
implicit none
contains
!********************************************************
integer function my_func_without_r() result(myresult)
myresult = 1
end function
integer function my_func_with_r() result(rresult)
rresult = 1
end function
end module my_mod
tests.py
#!/usr/bin/env python3
import fortran_mods
from fortran_mods import *
print("with r:", my_mod.my_func_with_r())
print("without r:", my_mod.my_func_without_r())
运行make pytest
并且FFLAGS+=-fdefault-real-8
包含在Makefile中时的输出为
with r: 0.0
without r: 1
否则就是
with r: 1.0
without r: 1
这里的问题肯定是F2PY如何包装Fortran函数,而不是Fortran代码本身 为了更深入地了解F2PY是如何包装函数的(特别是在事情没有按预期进行的情况下),将流程分成多个部分总是有帮助的(请参阅)。因此,首先创建一个签名文件,允许您查看F2PY如何解释代码。对于您的特定示例,请运行:
f2py -m fortran_mods -h my_mod.pyf my_mod.F90
这将生成一个签名文件my_mod.pyf
,看起来像这样:
python module fortran_mods ! in
interface ! in :fortran_mods
module my_mod ! in :fortran_mods:my_mod.F90
function my_func_without_r() result (myresult) ! in :fortran_mods:my_mod.F90:my_mod
integer :: myresult
end function my_func_without_r
function my_func_with_r() result (rresult) ! in :fortran_mods:my_mod.F90:my_mod
real :: rresult
end function my_func_with_r
end module my_mod
end interface
end python module fortran_mods
显然,F2PY错误地将my\u func\u与\u r
的结果变量rresult
识别为real
。您只需在my_mod.pyf
中将real::rresult
替换为所需的integer::rresult
,执行F2PY包装的下一步/第二步,并使用更正的签名文件进行编译:
f2py -c my_mod.pyf my_mod.F90
python脚本现在应该提供预期的输出
如果要包装许多函数,则可能不需要这种修改签名文件的方法。对F2PY造成困难的原因可能是函数定义使用了结果变量,而函数体中没有出现这些变量的类型定义(即F2PY问题,而不是Fortran问题)。如果将函数定义更改为,例如:
function my_func_with_r() result(rresult)
integer :: rresult
rresult = 1
end function
或
您可以像最初一样一步完成F2PY包装,并且仍然可以获得正确的输出
最后,我将对评论中提出的问题再投一票:当用F2PY包装函数时使用-fdefault-real-8
会带来麻烦。要执行此操作,F2PY将创建:
一个PythonC/API扩展模块(称为包装器模块)
实现一个Python扩展函数(用C编写,称为
包装器函数),它依次调用给定的Fortran过程
整个过程基于F2PY如何解释Fortran源代码中的数据类型-如果源代码是使用编译器标志编译的,这些标志会更改声明的数据类型,那么最终肯定会出现错误(与原始问题所涉及的
real
/integer
不匹配直接类似)。因此,变量和函数的数据类型应该在Fortran代码本身中明确设置,请参阅和了解Fortran的kind
参数,特别是与F2PY相关的参数。对不起,我无法复制此内容。你能展示一个完整的程序(或多个程序)来说明问题,告诉我们你是如何编译的,你使用的是什么版本的gfortran。嗯,我也不能用纯Fortran来复制它。我使用f2py从Python调用函数,所以这可能就是问题所在。我将稍后发布一个示例。@IanBush,我添加了一个显示问题的程序使用-fdefault-real-8是一个非常愚蠢的主意。-fdefault-real-8是一个坏主意,因为它可能不会做你认为它会做的事情。它违反了Fortran的关联规则,搞砸了等价性
、通用性
、参数传递和其他一些事情。不要用它。最好将代码复制到一个新文件中,并将其从REAL
正确地移植到DOUBLE-PRECISION
。在您或其他人质疑我对-default-real-8的理解之前,请查阅它的历史记录!谢谢,这非常有帮助。使用-fdefault-real-8
有什么危险?指定浮点感知的更好方法是什么?我编辑了我的答案,解释了使用-fdefault-real-8
的危险,并添加了其他问题/答案的链接,解释了如何在Fortran代码中正确定义浮点精度。
integer function my_func_with_r()
my_func_with_r = 1
end function