在IPython笔记本中使用fortranmagic排序数组:没有返回值

1 投票
2 回答
850 浏览
提问于 2025-04-18 08:59

我得说,我根本不是一个Fortran程序员。我通常只用Python和C++,不过有时候同事们写了一些很棒的Fortran函数,如果能在我的Python代码中用上,那效率会更高。我正准备通过IPython的魔法函数尝试一下f2py模块。

为了做一个简单的测试,我有一个冒泡排序的实现,我想在原地对一个Python列表进行排序(我把它转换成了一个按照Fortran风格在内存中排列的numpy数组;我想这样会比用Python列表更高效,对吧?)

不过,这个函数没有返回值(None),我在想我哪里出错了!?

安装和加载fortranmagic(使用f2py)的命令:

%install_ext https://raw.github.com/mgaitan/fortran_magic/master/fortranmagic.py
%load_ext fortranmagic

Fortran的冒泡排序代码:

%%fortran
SUBROUTINE fortran_bubblesort(a)
  REAL, INTENT(in out), DIMENSION(:) :: a
  REAL :: temp
  INTEGER :: i, j
  LOGICAL :: swapped = .TRUE.

  DO j = SIZE(a)-1, 1, -1
    swapped = .FALSE.
    DO i = 1, j
      IF (a(i) > a(i+1)) THEN
        temp = a(i)
        a(i) = a(i+1)
        a(i+1) = temp
        swapped = .TRUE.
      END IF
    END DO
    IF (.NOT. swapped) EXIT
  END DO
END SUBROUTINE fortran_bubblesort

执行结果:

x = np.asfortranarray([3,2,1])
y = fortran_bubblesort(x)
print(x, y)

结果:

[3 2 1] None

========

为了测试一般情况下是否能返回一个值,我运行了以下代码,结果很好:

%%fortran
SUBROUTINE fortran_sum(x, y, z)
    REAL, INTENT(in) :: x,y
    REAL, INTENT(out) :: z

    z = x + y

END SUBROUTINE fortran_sum

执行:

fortran_sum(3, 4)

返回:

7.0

2 个回答

0

我把问题中的原始Fortran代码搞定了,只需要把两个"REAL"的语句换成"REAL(kind=8)"的语句。这样一来,Fortran的变量就和Python的变量对上了。
另外,为了让程序能正常运行,避免输出"None",我建议加上以下几行(注意我把整数输入改成了浮点数,以确保匹配正确):

import numpy as np
x = np.asfortranarray([3.,0., 2.,1.])
print(x)
fortran_bubblesort(x)
print(x)

执行结果:

[ 3. 0. 2. 1.]
[ 0. 1. 2. 3.]

我还加了数字零,让它看起来更像Python的风格;-)

0

你遇到的问题跟数组的维度有关。看起来这个子程序是从一个模块中提取出来的,因为它使用了一个假定形状的虚拟数组 a。这就需要一个明确的接口,而我不太清楚 f2py 是怎么处理这个的。我之前只用过 f2py 来处理假定大小的虚拟数组,这个它处理得很好。下面是代码:

SUBROUTINE fortran_bubblesort(a,n)
  INTEGER, INTENT(in) :: n
  REAL, INTENT(in out), DIMENSION(n) :: a
  REAL :: temp
  INTEGER :: i, j
  LOGICAL :: swapped = .TRUE.

  DO j = SIZE(a)-1, 1, -1
    swapped = .FALSE.
    DO i = 1, j
      IF (a(i) > a(i+1)) THEN
        temp = a(i)
        a(i) = a(i+1)
        a(i+1) = temp
        swapped = .TRUE.
      END IF
    END DO
    IF (.NOT. swapped) EXIT
  END DO
END SUBROUTINE fortran_bubblesort

在这种情况下,f2py 会注意到 n 只是数组的维度,它会把这个参数变成 Python 函数中的一个可选参数。

撰写回答