从Python到Fortran传递子例程参数不正确

3

我将使用f2py编译一个数值模块,以供Python脚本使用。我已将代码简化为以下最小示例:

fd.f:

module fd
  ! Double precision real kind
  integer, parameter :: dp = selected_real_kind(15)

contains

subroutine lprsmf(th)
  implicit none
  real(dp) th
  write(*,*) 'th - fd',th
end subroutine lprsmf

end module fd

itimes.f:

subroutine itimes(th)
  use fd
  implicit none
  real(dp) th

  write(*,*) 'th - it',th
  call lprsmf(th)
end subroutine itimes

reprun.py:

import it

th = 200
it.itimes(th)

编译和运行所使用的命令如下(请注意,我在Windows下使用cmd):

gfortran -c fd.f
f2py.py -c -m it --compiler=mingw32 fd.o itimes.f
reprun.py

输出结果如下:
th - it  1.50520876326836550E-163
th - fd  1.50520876326836550E-163

我的第一个猜测是th在从reprun.py传递给子例程itimes时出现了问题。然而,我不理解这种行为,因为代码的完整版本包括其他输入,所有这些输入都被正确传递。当我从Fortran调用itimes时,我无法让它做同样的事情,所以我认为它与Python/Fortran接口有关。有人能提供任何关于为什么会出现这种行为的见解吗?
编辑:将reprun.py中的th = 200替换为th = 200.0会产生以下输出:
th - it  1.19472349365371216E-298
th - fd  1.19472349365371216E-298

@HighPerformanceMark,看一下修改后的代码。它仍然是垃圾值,但是不同于之前的那个。 - astay13
1个回答

1
将您的itimes子例程也包装在一个模块中。这是我所做的:

itimes.f90:

module itime

contains

subroutine itimes(th)
  use fd
  implicit none
  real(dp) th

  write(*,*) 'th - it',th
  call lprsmf(th)
end subroutine itimes

end module

编译和运行:

gfortran -c fd.f90
c:\python27_w32\python.exe c:\python27_w32\scripts\f2py.py -c -m it --compiler=mingw32 fd.f90 itimes.f90

运行 reprun.py:

import it

th = 200
it.itime.itimes(th)

输出:

 th - it   200.00000000000000     
 th - fd   200.00000000000000     

玩了一会儿,我发现在itimes.f中不需要模块声明,似乎关键点是将fd.f90传递给f2py而不是fd.o。你知道为什么会这样吗? - astay13
@astay13 哦,你可能是对的,我只是出于习惯改变了那个。不确定,我只尝试过将实际的Fortran源代码传递给f2py。我仍然建议始终将代码包装在模块中,这样可以避免许多Fortran陷阱。 - bananafish
@astay13 -- 你需要传递源代码而不是.o文件。基本上,f2py是一个Fortran解析器(加上一点)它用C代码和Python API包装您的Fortran代码。然后使用系统上找到的任何编译器将整个内容编译为共享对象,该对象可以由Python加载。如果您给f2py一个对象文件--它远远不够复杂,无法反向工程已经编译的代码并生成Python接口。 - mgilson
@mgilson,我一直在使用Fortran对象文件编译代码,并且在遇到这个问题之前一直运行良好。我认为这可能与我第一次尝试将“real”参数传递到主子程序有关。 - astay13

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接