在Fortran 90中传递参数的聪明方式

5

我是一名Fortran初学者。我正在尝试编写一个子程序,该子程序将从主程序中获取四个参数,然后输出涉及最初传入的四个参数的数组到主程序中。有什么好的/聪明的方法可以做到这一点吗?

例如,在我的下面的测试程序中,我在主程序中创建了四个实数变量(abcd)。然后,我将这些实数变量传递给名为mysub的子程序。我希望mysub能够接收abcd,使用它们填充名为o的2x2数组,然后将o发送到主程序以供显示(和可能的修改)。因此,我尝试了以下内容:

SUBROUTINE mysub(w,x,y,z)
  IMPLICIT NONE
  REAL, INTENT(IN) :: w, x, y, z
  REAL, DIMENSION(:,:), ALLOCATABLE, INTENT(OUT) :: o

  ALLOCATE(o(2,2))
  o(1,1)=w
  o(1,2)=x
  o(2,1)=y
  o(2,2)=z
END SUBROUTINE mysub
END MODULE testsubs

PROGRAM test
  USE testsubs
  IMPLICIT NONE
  REAL :: a=1.1, b=2.2, c=3.3, d=4.4

  CALL mysub(a, b, c, d)

  PRINT *, o(1,1), o(1,2)
  PRINT *, o(2,1), o(2,2)
END PROGRAM test

但是,我遇到了以下错误:
test.f90:10.53:

  REAL, DIMENSION(:,:), ALLOCATABLE, INTENT(OUT) :: o
                                                     1
Error: Symbol at (1) is not a DUMMY variable

我理解为编译器不知道o是什么,因为在子程序头部的参数列表中没有o。即SUBROUTINE mysub(w,x,y,z)。所以我可能需要在头部包括o。接下来,我尝试以下更改(使用!...表示更改或添加):
SUBROUTINE mysub(w,x,y,z,o) !...
  IMPLICIT NONE
  REAL, INTENT(IN) :: w, x, y, z
  REAL, DIMENSION(:,:), ALLOCATABLE, INTENT(OUT) :: o

  ALLOCATE(o(2,2))
  o(1,1)=w
  o(1,2)=x
  o(2,1)=y
  o(2,2)=z
END SUBROUTINE mysub
END MODULE testsubs

PROGRAM test
  USE testsubs
  IMPLICIT NONE
  REAL :: a=1.1, b=2.2, c=3.3, d=4.4
  REAL, DIMENSION(:,:), ALLOCATABLE :: o !...

  CALL mysub(a, b, c, d, o) !...

  PRINT *, o(1,1), o(1,2)
  PRINT *, o(2,1), o(2,2)
  DEALLOCATE(o) !...
END PROGRAM test

这样做似乎很好,我得到了正确的输出:

   1.1000000       2.2000000
   3.3000000       4.4000001

但是,我的问题是,这样做好吗?在这个工作示例中,我在子程序和主程序中都声明了数组 o。这似乎可能会令人困惑,因为我认为这意味着我需要注意 要么 子程序 要么 主程序分配 o(但不是同时分配,为了避免错误消息)。有没有更聪明的方法来做到这一点 - 将一个数组从子程序发送到主程序?感谢您的时间。
3个回答

4
您的解决方案是把“o”作为一个输出参数,这很好。如果没有将“o”作为参数传递,子程序中的变量“o”和主程序中的变量“o”之间就没有联系,因此在主程序中没有声明或分配变量。除了@ja72提供的解决方案之外,另一种解决方案是更改您的方法:将“o”作为一个输入/输出参数传递给子程序,并在主程序中分配它。可能的优点是代码中分配和释放更接近且成对出现。可能的缺点是,根据程序逻辑和设计,数组维度可能最适合由子程序知道。
附言:如果您在主程序中分配数组,并且在子程序中实际上不使用可分配属性(即,您不分配或释放它),则您不必在子程序中声明具有可分配属性的数组--这是一个有用的简化。在这种情况下,“输出意图”可能是适当的。但是,如果您在主程序中分配数组并希望将该状态传递给子程序,则参数状态不能为“输出意图”。 “输出意图”会在进入过程时自动释放参数。

子程序内参数的顺序是否必须与虚拟参数传递的顺序匹配?例如:REAL,INTENT(IN):: z,y,x,w是可以接受的吗? - Herman Toothrot

1

从你的问题中不清楚你是否预先知道数组的大小,但是如果你知道,通常最好的做法是在同一位置分配和释放数组,甚至更好的做法是在可能时让编译器分配内存。

我的做法:

  • 如果大小在编译时已知: 在主程序中声明数组,在子程序中使用intent(out)

  • 如果大小仅在运行时已知: 在主程序中分配,在子程序中使用intent(out)并在主程序中释放。

函数最适合小输出,因为需要复制输出。


1

如果你想返回一个数组,你可以a) 将它添加到参数中,并使用INTENT(OUT),就像你的示例#2一样,在子程序内进行分配;或者b) 创建一个函数并在外部分配数组:

FUNCTION myfun(w,x,y,z,n,m)
IMPLICIT NONE
INTEGER, INTENT(IN) :: n,m
REAL, DIMENSION(n,m) :: myfun
REAL, INTENT(IN) :: w,x,y,z

  myfun(1,1)=w
  myfun(1,2)=x
  myfun(2,1)=y
  myfun(2,2)=z

END FUNCTION
END MODULE testsubs

PROGRAM test
  USE testsubs
  IMPLICIT NONE
  REAL :: a=1.1, b=2.2, c=3.3, d=4.4
  REAL, DIMENSION(:,:), ALLOCATABLE :: o !...

  ALLOCATE(o(2,2))
  o  = myfun(a,b,c,d,2,2)

  PRINT *, o(1,1), o(1,2)
  PRINT *, o(2,1), o(2,2)
  DEALLOCATE(o) !...
END PROGRAM test

实际上,我认为你的解决方案更清晰。


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