【问题标题】:Function composition in FortranFortran 中的函数组合
【发布时间】:2016-07-26 00:49:12
【问题描述】:

我想在 Fortran 中创建一个 function composition。这个想法是如果我有 f(x) 和 g(x),我想找到 f(g(x))。在pythonBetter Function Composition in Python中语法很简单。

这是一个示例 Fortran 代码:

module test10
implicit none
contains
    function f5x (x)
        real :: f5x
        real, intent (in) :: x
        f5x = 5.00*x
    end function f5x

    function f10x (x)
        real :: f10x
        real, intent (in) :: x
        f10x = 10.00*x
    end function f10x


end module test10


program call_test10
    use test10
    implicit none
    real :: val1, val2, input


    interface 
    real function fx_new (y)
        real, intent (in) :: y
    end function fx_new
    end interface


    input=1.0
    write (*,*) 'Invoking f5x'
    val1 = f5x(1.0)
    write (*,*) val1
    write (*,*) 'Invoking f10x'
    val1 = f10x(1.0)
    write (*,*) val1
    write (*,*) 'Invoking f10x(f5x)'
    procedure (fx_new), pointer :: ptr1 => f5x
    procedure (fx_new), pointer :: ptr2 => f10x
    val2 = ptr2(ptr1)
    write (*,*) val2

 end program call_test10

语句val1 = f5x(1.0)val1 = f10x(1.0) 自行运行。但是当涉及到函数组合时,我不知道如何在 Fortran 中实现。我想评估 f10x(f5x),然后想为 x 赋值。有什么想法吗?

如果我包含一个模块文件并且函数返回类型、参数数量和参数类型匹配,Fortran 编译器可以决定在包含的文件中执行哪个函数吗?我想知道的另一件事是我可以摆脱接口(通过使用过程指针或其他东西)吗?执行外部函数的接口的整个想法让我感到困惑,所以如果可能的话,请提出一种不使用接口执行外部函数的方法。我知道关键字external,但它适用于更早的版本(尽管它继续适用于较新的标准)。

由于过程指针采用较新的标准(2003、2008、...),我将使用 Fortran 标准 2008。

【问题讨论】:

  • 在 fortran 中无法关闭。
  • 如果不借助具有指针类型绑定过程的用户定义派生数据类型和通过c_f_pointer in @987654329 中的过程实现的 C 语言样式转换,我认为您无法完成此任务@。无论如何,函数组合违反了在 Fortran 中传递参数的方式。见:software.intel.com/en-us/blogs/2009/03/31/…

标签: fortran function-composition


【解决方案1】:

这是一个我已经在这里展示过的例子Dynamic function creation from another function(你搜索过吗?)。我认为这个问题不是完全重复的,所以我重用而不是关闭。其他人可以查看此内容。

module ComposeObj
  !here use modules defining your working kind as you wish

  implicit none

  private
  public Compose

  abstract interface
    !declare fce as a function of the type you wish, probably a real function of a real variable    
  end interface

  type Compose
    private
    procedure(fce),pointer,nopass :: f1 => null(),f2=>null()
  contains
    procedure,public :: call => helper
  endtype Compose

  interface Compose
    procedure NewCompose
  end interface

 contains

  function NewCompose(f,g)
    procedure(fce) :: f,g
    type(Compose) :: NewCompose

    NewCompose%f1 => f
    NewCompose%f2 => g
  end function NewCompose

  pure real(work_kind) function helper(this,x)
    class(Compose),intent(in) :: this
    real(work_kind),intent(in) :: x
    helper = this%f1(this%f2(x))
  end function helper

end module ComposeObj

基本上你必须提前准备可以进行函数组合的类。你不能只是动态地创建一个闭包。

但是您可以动态地将函数指针分配给您想要的函数,而不必提前完成。

您必须使用 %call(x) 方法来使用它,您不能覆盖 (),因为它不是 Fortran 中的运算符(它是 C++ 中的)。

   type(Compose) :: f1_f2
   f1_f2 = Compose(f1, f2)

   val2 = f1_f2%call(x)

在本地,您可以使用内部函数。我和其他人在这里多次展示过它。不值得一一重复,只是一个代码示例:

  val2 = composed_f1_f2(x)

contains

  function composed_f1_f2(x)
    real :: composed
    real, intent(in) :: x
    composed = f1(f2(x))
  end function

【讨论】:

    【解决方案2】:

    我认为这不可能如你所愿。

    在我开始之前:即使在允许这种事情的语言中,如果你输入类似ptr2(ptr1) 的东西,结果将是一个函数,而不是一个值。您将无法将其存储在 REAL 变量中。

    您可以编写自己的函数,如下所示:

    function my_func(x)
        use test10, only: f5x, f10x
        implicit none
        real, intent(in) :: x
        real :: my_func
        my_func = f10x(f5x(x))
    end function my_func
    

    【讨论】:

      【解决方案3】:

      这可能有点幼稚,但 Fortran 允许将函数作为参数传递,因此您可以:

      real function f(x, g)
      external g
      real x
      is_g_present = PRESENT(g) 
      
      if is_g_present:
          ! Do something with g and x
      else:
          ! Do f(x) normally
      endif
      return
      

      这将允许您将 f 称为 f(x) 或 f(x,g)。这并不完全符合您的要求,但对于 Fortran 来说是一个不错且简单的解决方法。

      (伪代码,因为我没有机器可以测试我现在没有写完全愚蠢的东西,我会写这个只是作为评论,但我目前缺乏声誉,抱歉)

      【讨论】:

      • external 语句是维护的噩梦。
      猜你喜欢
      • 2011-04-19
      • 2014-08-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-23
      • 1970-01-01
      • 1970-01-01
      • 2021-01-19
      相关资源
      最近更新 更多