Вызов подпрограммы несколько раз с разными функциями в качестве аргумента каждый раз

Я достаточно новичок, чтобы не знать терминологию, поэтому я не могу искать в Интернете ответ на этот вопрос.

Не раз в программировании мне хотелось сделать что-то подобное.

A и B - подпрограммы, c и d - функции. Каждый из A и B вызывает внутри себя функцию несколько раз.

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

Эта структура не работает. Мне сказали, что Фортран не поддерживает псевдонимы функций, по крайней мере, в этом контексте. (Большинство результатов поиска с использованием «псевдонимов» относятся к переменным псевдонимов, а не к функциям, поэтому я не нашел ответа.)

Итак, какую структуру я могу использовать для этого без необходимости писать несколько версий A и B?


person Tristan Klassen    schedule 28.11.2012    source источник
comment
Вы спрашиваете, как передать функцию процедуре? (В отличие от передачи результата оценки функции процедуре, как показано в вашем примере кода.)   -  person IanH    schedule 29.11.2012


Ответы (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 и даже раньше, чем этот External будет делать то, что вы хотите, но имеет меньше возможностей проверки ошибок

person Ian Bush    schedule 29.11.2012

вызов A (c (x)) выглядит как оцените c (x) и передайте его подпрограмме A, как говорит IanH в своем комментарии.

Если вы хотите передать функцию «C», которая принимает аргумент типа X, подпрограмме A, есть несколько способов сделать это.

Как уже упоминалось, указатели на процедуры - это новый способ. Хотя существует очень мало компиляторов, поддерживающих весь стандарт Fortran 2003, эта часть широко поддерживается.

Вот пример, адаптированный из массивов указателей функций в Фортране

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

Вызовы «call fancy (f_ptr, 2.0, answer)» выглядят одинаково, но при изменении функции, на которую указывает указатель функции f_ptr, в подпрограмму fancy передается другая функция.

Это компилируется как с gfortran (версии с 4.4 по 4.7), так и с ifort.

person M. S. B.    schedule 29.11.2012

Я думаю, что ответ M.S.B. описывает, что вы имеете в виду под псевдонимом функций; терминология Фортрана - «указатели на процедуры». В качестве альтернативы этому и ответу Яна вы также можете использовать фиктивные аргументы процедуры (которые не обязательно являются указателями). Обратите внимание, что любое объявление procedure поддерживается только с F2003, но 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

Теперь вы можете передать f1 и f2 прямо в a и b, и результат будет таким, как ожидалось:

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
person sigma    schedule 29.11.2012

Если я понимаю, что вы пытаетесь сделать:

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
person bob.sacamento    schedule 01.12.2012