每次使用不同的函数作为参数多次调用子例程

时间:2012-11-28 23:42:11

标签: fortran fortran90 fortran95

我已经足够新手不知道术语了,所以我无法在网上搜索答案。

在编程方面,我不止一次想做这样的事情。

A和B是子程序,c和d是函数。 A和B各自在其中多次调用函数。

call A(c(x))
call A(d(x))
call B(c(x))
call B(d(x))

此结构不起作用。我被告知Fortran不支持函数别名,至少在这种情况下是这样。 (大多数涉及“别名”的搜索结果是指别名变量而不是函数,这就是我没有找到答案的原因。)

那么我可以用什么结构来做这个而不必编写A和B的多个版本?

4 个答案:

答案 0 :(得分:4)

我不完全确定我理解你想要什么,但它是否类似以下内容?

Program f

  Implicit None

  Interface
     Integer Function c( x )
       Implicit None
       Integer, Intent( In ) :: x
     End Function c
     Integer Function d( x )
       Implicit None
       Integer, Intent( In ) :: x
     End Function d
  End Interface

  Call a( 3, c )
  Call a( 4, d )

  Call b( 5, c )
  Call b( 6, d )

Contains

  Subroutine a( x, func )

    Integer, Intent( In ) :: x
    Interface
       Integer Function func( x )
         Implicit None
         Integer, Intent( In ) :: x
       End Function func
    End Interface

    Write( *, * ) 'In a. Func = ', func( x )

  End Subroutine a

  Subroutine b( x, func )

    Integer, Intent( In ) :: x
    Interface
       Integer Function func( x )
         Implicit None
         Integer, Intent( In ) :: x
       End Function func
    End Interface

    Write( *, * ) 'In b. Func = ', func( x )

  End Subroutine b

End Program f

Integer Function c( x )
  Implicit None
  Integer, Intent( In ) :: x
  c = 2 * x
End Function c

Integer Function d( x )
  Implicit None
  Integer, Intent( In ) :: x
  d = 10 * x
End Function d
Wot now? gfortran -std=f95 f.f90 
Wot now? ./a.out
 In a. Func =            6
 In a. Func =           40
 In b. Func =           10
 In b. Func =           60
Wot now? 

一个替代方法是程序指针,但你需要一个f2003编译器,那些并不常见 - 上面很好回到f90,甚至早于外部会做你想要的,但错误更少检查能力

答案 1 :(得分:4)

调用A(c(x))看起来像是评估c(x)并将其传递给子程序A,正如IanH在他的评论中所说的那样。

如果要传递一个函数“C”,它将类型为X的参数传递给子程序A,有几种方法可以做到这一点。

如前所述,过程指针是一种新方法。虽然支持所有Fortran 2003标准的编译器极少,但这一部分得到了广泛的支持。

以下是改编自Function pointer arrays in Fortran

的示例
module ProcsMod

  implicit none

contains

function f1 (x)
  real :: f1
  real, intent (in) :: x

  f1 = 2.0 * x

  return
end function f1


function f2 (x)
   real :: f2
   real, intent (in) :: x

   f2 = 3.0 * x**2

   return
end function f2


subroutine fancy (func, x, answer)

   real, intent (in) :: x
   real, intent (out) :: answer

   interface AFunc
      function func (y)
         real :: func
         real, intent (in) ::y
      end function func
   end interface AFunc

   answer = func (x)

end subroutine fancy

end module  ProcsMod


program test_proc_ptr

  use ProcsMod

  implicit none

  interface
     function func (z)
        real :: func
        real, intent (in) :: z
     end function func
  end interface

  procedure (func), pointer :: f_ptr => null ()

  real :: answer

  f_ptr => f1
  call fancy (f_ptr, 2.0, answer)
  write (*, *) answer

  f_ptr => f2
  call fancy (f_ptr, 2.0, answer)
  write (*, *) answer


  stop

end program test_proc_ptr

调用“fancy(f_ptr,2.0,answer)”看起来是一样的,但通过改变函数指针f_ptr指向的函数,将一个不同的函数传递给子程序fancy。

这包括gfortran(版本4.4到4.7)和ifort。

答案 2 :(得分:1)

我认为M.S.B.的答案描述了你对函数混叠的意思; Fortran术语是“程序指针”。作为这个和Ian的答案的替代方法,您还可以使用过程伪参数(不一定是指针)。请注意,自F2003起,任何procedure声明都受支持,但gfortran 4.7和ifort 13都支持此声明。它可以使用或不使用(抽象)接口块来完成:

module dummy_procedure
  implicit none

  abstract interface
    real function myfunc(x)
      real, intent(in) :: x
    end function
  end interface

contains      
  subroutine a(func)
    ! Using the interface block:
    procedure(myfunc) :: func         
    print*, 'a:', func(.5)
  end subroutine

  subroutine b(func)
    ! Using the explicit interface of a known procedure:
    procedure(f1) :: func  
    print*, 'b:', func(.5)
  end subroutine

  real function f1(x)
    real, intent(in) :: x
    f1 = 2.0 * x
  end function

  real function f2(x)
    real, intent(in) :: x
    f2 = 3.0 * x**2
  end function
end module

现在,您可以将f1f2直接传递到ab,输出符合预期:

program main
  use dummy_procedure
  call a(f1)  ! a: 1.0
  call a(f2)  ! a: 0.75
  call b(f1)  ! b: 1.0
  call b(f2)  ! b: 0.75
end program

答案 3 :(得分:0)

如果我理解你要做的事情:

1)在模块中定义你的功能。

2)使用模块。

3)将函数和输入数据作为单独的参数提供给子程序。

这是一个适合我的代码:

module iterfuncs
contains

! two example functions:
function approach_golden_ratio(a) result(agr)
  agr=1./a+1.
end function approach_golden_ratio

function approach_other_ratio(a) result(aor)
  aor=1./(a-1)
end function approach_other_ratio

end module



program use_some_functions

use iterfuncs

real :: final_res

final_res=2.3
! call subroutine with 1st function
call iterate(final_res,approach_golden_ratio)
print *,final_res

final_res=2.3
! call subroutine with 2nd function
call iterate(final_res,approach_other_ratio)
print *,final_res

end program



subroutine iterate(res,func)

use iterfuncs

do n=1,100
  res=func(res)
enddo

return

end subroutine