通过子程序将一组变量值传递给没有公共块的函数都有哪些方法?

Posted

技术标签:

【中文标题】通过子程序将一组变量值传递给没有公共块的函数都有哪些方法?【英文标题】:What are the ways to pass a set of variable values through the subroutine to a function without common block?通过子程序将一组变量值传递给没有公共块的函数有哪些方法? 【发布时间】:2015-11-29 21:49:12 【问题描述】:

我不想在我的程序中使用公共块。我的主程序调用一个调用函数的子程序。该函数需要来自子程序的变量。

将一组信息从子程序传递给函数的方法有哪些?

program
...

call CONDAT(i,j)

end program

SUBROUTINE CONDAT(i,j)

common /contact/ iab11,iab22,xx2,yy2,zz2
common /ellip/ b1,c1,f1,g1,h1,d1,b2,c2,f2,g2,h2,p2,q2,r2,d2
call function f(x)
RETURN
END

function f(x)
common /contact/ iab11,iab22,xx2,yy2,zz2
common /ellip/ b1,c1,f1,g1,h1,d1,b2,c2,f2,g2,h2,p2,q2,r2,d2
end

【问题讨论】:

程序接受参数。将数据作为参数传递,并在调用其他人时使用它们。 您能否提供一些具体的代码,以显示您实际上不理解的内容?正如凯西所说,将参数传递给子例程或过程基本上没有区别,所以我有点不清楚你的问题的目的是什么。 感谢凯西和 Haraldkl。我已经用示例编辑了我的问题。我的问题是如何在不使用公共块的情况下将公共块“contact and ellip”中的变量从子程序“CONDAT”传递给函数 f(x)。 @SadiaF 我会使用模块以更简洁的格式实现这一点...见下文 请注意,如果您确实需要 f77 方法,唯一的替代 common 是将所有内容作为函数参数传递。 (如果你不是故意的,你应该删除那个标签) 【参考方案1】:

以下是您如何实现此目标的示例...

代码改编自 BFGS 方法,以展示如何在模块中传递函数和调用其他函数...

我在这里使用:

嵌套在其他子例程中的私有函数 将变量从子例程传递到嵌套函数 将函数作为可在模块块外定义的函数的参数传递

希望这将为您涵盖所有内容...

Module Mod_Example

Private :: private_func

   SUBROUTINE test_routine(res,start,fin,vector,func,dfunc)
      IMPLICIT NONE
      REAL, DIMENSION(:), INTENT(IN) :: res, start, fin
      REAL, DIMENSION(:), INTENT(INOUT) :: vector

      INTERFACE
         FUNCTION func(vector)                                      
            IMPLICIT NONE                                      
            REAL, DIMENSION(:), INTENT(IN) :: vector                
            REAL :: func                                       
         END FUNCTION func                                     

         FUNCTION dfunc(vector)                                     
            IMPLICIT NONE                                      
            REAL, DIMENSION(:), INTENT(IN) :: vector               
            REAL, DIMENSION(size(vector)) :: dfunc                  
         END FUNCTION dfunc                                    
      END INTERFACE

      ! do stuff with p

      private_func(res,start,fin,vector,func,dfunc) 

      ! do stuff
   END SUBROUTINE test_routine

   SUBROUTINE private_func(res,start,fin,vector,func,dfunc)
      IMPLICIT NONE
      REAL, DIMENSION(:), INTENT(IN) :: res, start, fin
      REAL, DIMENSION(:), INTENT(INOUT) :: vector
      INTERFACE
         FUNCTION func(vector)            
            REAL, DIMENSION(:), INTENT(IN) :: vector
            REAL :: func
         END FUNCTION func
         FUNCTION dfunc(vector)
            REAL, DIMENSION(:), INTENT(IN) :: vector
            REAL, DIMENSION(size(vector)) :: dfunc
         END FUNCTION dfunc     
      END INTERFACE   

      ! do stuff             
   END SUBROUTINE private_func

END Mod_Example
funcdfunc 将在使用 MODULE Mod_Example 的程序代码中声明,顶部有一个接口块。 变量:resstart 等可以在主程序块中用值声明并作为参数传递给SUBROUTINE test_routineSUBROUTINE test_routine 将使用传递给它的变量调用 private_func

您的主程序将如下所示:

Program Main_Program
   USE Mod_Example
   INTERFACE
      FUNCTION func(vector)            
         REAL, DIMENSION(:), INTENT(IN) :: vector
         REAL :: func
      END FUNCTION func
      FUNCTION dfunc(vector)
         REAL, DIMENSION(:), INTENT(IN) :: vector
         REAL, DIMENSION(size(vector)) :: dfunc
      END FUNCTION dfunc     
   END INTERFACE

   ! do stuff       

   ! calls test_routine form module
   ! uses dfunc and func defined below
   call test_routine(res,start,fin,vector,func,dfunc)

   ! do stuff
END PROGRAM Main_Program

! define dfunc and nfunc for passing into the modular subroutine
FUNCTION func(vector)
   IMPLICIT NONE
   REAL, DIMENSION(:), INTENT(IN) :: vector
   REAL :: func

   nfunc = vector
END FUNCTION func

FUNCTION dfunc(vector)
   IMPLICIT NONE
   REAL, DIMENSION(:), INTENT(IN) :: vector
   REAL, DIMENSION(size(vector)) :: dfunc   

   dfunc = vector
END FUNCTION dfunc

【讨论】:

谢谢亚历山大。我一定会尝试 MODULE 并让您知道它是否有效。那么没有公共块或模块就没有办法传递信息了吗? @SadiaF 该模块不是严格要求的。我也不确定,你是否真的想要这个函数作为参数。从您的代码来看,它看起来就像一个正常的调用。 严格来说你是对的,这只是一个普通的调用,但我添加了这个函数来演示如何做到这一点。我还发现模块使大型项目更容易处理 当然应该使用模块!我只是在她的评论中提到了 SadiaFs 的问题,这是否可以在没有模块的情况下完成:是的,可以,但我强烈建议不要这样做。我什至应该更新下面的示例以使用两个模块。 谢谢@Alexander McFarlane!【参考方案2】:

所以,基本上你可以通过以下方式解决这个问题:

SUBROUTINE CONDACT(i,j, iab11,iab22,xx2,yy2,zz2,b1,c1,f1,g1,h1,d1,b2,c2,f2,g2,h2,p2,q2,r2,d2,res)
  !declaration to all those parameters and res
  res = f(x)
END SUBROUTINE CONDACT

function f(x,iab11,iab22,xx2,yy2,zz2,b1,c1,f1,g1,h1,d1,b2,c2,f2,g2,h2,p2,q2,r2,d2)
!declaration to all those parameters
end function f

program
  ...

  call CONDAT(i,j,iab11,iab22,xx2,yy2,zz2,b1,c1,f1,g1,h1,d1,b2,c2,f2,g2,h2,p2,q2,r2,d2,res)

end program

即只是传递参数。 强烈建议使用模块,请参阅 Alexander McFarlane 的回答,尽管它不是必需的。 Alexander McFarlane 展示了如何将 f 作为参数传递给子例程,以便您可以在子例程中使用不同的函数,但您的代码似乎不需要这样做。

现在,这是一个非常长的参数列表,您可能不想一直携带这些参数。 处理此问题的常用方法是将这些参数放入 derived datatype 中,然后将其传递。 像这样:

!> A module implementing ellip related stuff.
module ellip_module

  implicit none

  type ellip_type
    !whatever datatypes these need to be...
    integer :: b1,c1,f1,g1,h1,d1,b2,c2,f2,g2,h2,p2,q2,r2,d2
  end type
end module ellip_module


!> A module implementing condact related stuff.
module condact_module
  use ellip_module ! Make use of the ellip module to have the type available

  implicit none

  type condact_type
    !whatever datatypes these need to be...
    integer :: iab11,iab22,xx2,yy2,zz2
  end type

  contains

  subroutine condact(i,j, con, ellip, res)
     integer :: i,j
     type(condact_type) :: con
     type(ellip_type) :: ellip
     real :: res

     real :: x
     res = f(x, con, ellip)
  end subroutine condact

  function f(x, con, ellip) result(res)
    real :: x
    real :: res
    type(condact_type) :: con
    type(ellip_type) :: ellip

    res = !whatever this should do
  end function f
end module condact_module


!> A program using the condact functionality.
program test_condact
  use ellip_module
  use condact_module

  implicit none

  type(condact_type) :: mycon
  type(ellip_type) :: myellip
  integer :: i,j
  real :: res

  call condact(i,j, mycon, myellip, res)
end program test_condact

这只是一个粗略的草图,但我觉得这就是你要找的东西。

【讨论】:

@SadiaF 没问题,我希望你能整理出你的公地。据我所知,OpenMP 并行化的最佳选择是在你的 ford 例程中定义 ellip 和 condact 类型的局部变量并将它们传递下去。由于您的 OpenMP 循环在外部,因此这些将是完全私有的,无需多言。 本地化变量不起作用。作为子程序覆盖和共享变量。我的旧代码写的是 FORTRAN77。模块在 77 上不起作用!我想知道下一步该怎么做! @SadiaF 我不太清楚你所说的覆盖是什么意思。通过覆盖,我了解到例程只是使用相同的内存来处理独立的事情,这样一个结果就会被另一个忽略。如果不是这种情况,您需要有一些非局部变量,您仍然可以通过上述方法实现,但并行化策略将取决于数据如何通过您的例程。类型和模块都不能在 F77 中工作,但这不是问题,因为现在所有的编译器都是 F90。 @SadiaF 也许您可以在codereview.stackexchange.com 上发布一个更完整、更有效的代码示例,并带有 Fortran 标记。 Code Review 致力于代码改进。注意,你不需要坚持 F77,即使代码的其他部分是 F77。出于实际目的,F77 是 F90 的子集,这意味着您的代码库可能与 F77 一样是有效的 F90 代码。如上所述,我们现在基本上只有 F90 编译器,F77 兼容性是一个争论点。在编写新代码或修改现有部分时,您不应感到自己受到限制。 我的代码太大,无法发布!我已经尝试过使用模块和公共块并得到相​​同的结果。不知何故,线程 0 不能使用线程安全变量!我在这里发布了我的问题***.com/questions/32596809/…【参考方案3】:

您在这里关心的是关联:您希望能够将函数f 中的实体与子程序condat 中的实体相关联。存储关联是实现此目的的一种方式,这就是 common 块正在做的事情。

还有其他有用的关联形式。这些是

使用关联 主机关联 参数关联

参数关联在haraldkl's answer中描述。

使用关联来自于类似的模块

module global_variables
  implicit none     ! I'm guessing on declarations, but that's not important
  public   ! Which is the default
  real b1,c1,f1,g1,h1,d1,b2,c2,f2,g2,h2,p2,q2,r2,d2,xx2,yy2,zz2
  integer iab11,iab22
end module

subroutine condat(i,j)
  use global_variables   ! Those public things are use associated
  ...
end subroutine

function f(x)
  use global_variables   ! And the same entities are accessible here
  ...
end function

主机关联正在访问主机可访问的实体。这里的主机可以是一个模块或程序

module everything
  integer iab11,...
  real ...
 contains
  subroutine condat(i,j)
    ! iab11 available from the host module
  end subroutine

  function f(x)
    ! iab11 available from the host module
  end function
end module

甚至是子程序本身

subroutine condat(i,j)
  integer iab11,...
  real ...
 contains
  function f(x)
    ! Host condat's iab11 is accessible here
  end function
 end subroutine

【讨论】:

非常感谢!我将使用“使用关联”并让您知道它是否有效。

以上是关于通过子程序将一组变量值传递给没有公共块的函数都有哪些方法?的主要内容,如果未能解决你的问题,请参考以下文章

如何从swift将一组浮点数组传递给C++函数

使用 pandas 将一组值传递给 bigquery 查询

将一组指针投射到其他对象?

如何将一组选中/未选中的复选框值传递给 PHP 电子邮件生成器?

如何将过程中的变量值传递给 Apex 中的 Javascript 函数

将循环中的变量值传递给jquery函数