2014-10-31 3 views
0

Я ищу, чтобы передать функцию функции, которая будет оцениваться в другой функции, возможно ли это? Я пытаюсь иметь функцию, которая может численно интегрировать общую функцию. В моей реальной проблеме есть другие значения, поэтому я не хочу иметь внешнюю функцию.Функция утверждения функции Fortran для функции

Редактировать 2014/11/1 2:22 GMT

Существовало несколько ошибок в коде @IanH положить. Это код, который работает после того, как я забочусь о клопах.


program trapezoidZ 
    implicit none 

    ! main program global variables and constants here. 

    call main 
contains 
subroutine main 
    real :: u, integral1 
    integer :: i 
    integer, parameter :: n = 5000 
    ! delete declaration of trapezoid_integration and f. 

    integral1 = trapezoid_integration(TrigSin, n, 0., 3.14159/2.0) 

    write (*,*) "I - Trap = ",1 - integral1 
end subroutine main 

function my_f(u) 
    real :: my_f 
    real, intent(in) :: u 

    my_f = (u**4)*EXP(u)/((EXP(u)-1.0)**2) 
end function my_f 

function TrigSin(u) result(my_f) 
    real :: my_f 
    real, intent(in) :: u 

    my_f = sin(u) 
end function TrigSin 

function trapezoid_integration (f, n, start_val, end_val) result (integral) 
    ! delete declaration of integrand (assuming you have it). 
    procedure(my_f) :: f 

    integer :: n 
    real :: start_val, end_val 
    real :: integral,u,h 
    integer :: i 

    integral = 0.0 

    do i=0,n 
     u = start_val + ((end_val - start_val)*i)/n 

     ! implement Eqn G.4 
     if ((i.eq.0).or.(i.eq.n)) then 
      integral = integral+integrand(f, u) 
     else 
      integral = integral+(2.0*integrand(f, u)) 
     end if 

    end do 

    h=(end_val - start_val)/n 
    integral = (h/2.0)*integral 

end function trapezoid_integration 

function integrand(f, x) result (value) 
    implicit none 
    real :: x 
    real :: value 
    real :: f 

    if (x .lt. 0.00001) then 
     x = 0.00001 
    end if 

    value = f(x) 
end function integrand 

end program trapezoidZ 

Ниже это исходный код. НЕ ИСПОЛЬЗОВАТЬ


program trapezoidZ 
    implicit none 
    integer, parameter :: n = 10 
    real :: u, integral 
    integer :: i 
    real :: f, trapezoid_integration 

    f(u) = (u**4)*EXP(u)/((EXP(u)-1.0)**2) 

    integral = trapezoid_integration(f, n, 0.2, 3.0) 
    write (*,*) '#trapezoidal integration = ',integral 

end program trapezoidZ 

function trapezoid_integration(f, n, start_val, end_val) 
    implicit none 
    integer :: n 
    real :: start_val, end_val 
    real :: f 
    real :: integral,u,h 
    integer :: i 

    integral = 0.0 

    do i=0,n 
    u = start_val + ((end_val - start_val)*i)/n 

    ! implement Eqn G.4 
    if ((i.eq.0).or.(i.eq.n)) then 
     integral = integral+integrand(f, u) 
    else 
     integral = integral+(2.0*integrand(f, u)) 
    end if 

    end do 

    h=(end_val - start_val)/n 
    integral = (h/2.0)*integral 

end subroutine trapezoid_integration 

function integrand(f, x) result (value) 
    implicit none 
    real :: x 
    real :: value 
    real :: f 

    if (x .lt. 0.00001) then 
    x = 0.00001 
    end if 

    value = f(x) 
end function integrand 

ответ

4

Это не разрешается в стандарте Fortran - функция утверждение не в списке разрешенных типов процедур в ограничении C1235 в Fortran 2008.

Однако, поскольку это ограничение указывает, вы не ограничены внешними функциями. Начиная с Fortran 90, фактический аргумент может быть процедурой модуля. Начиная с Fortran 2008, это может быть внутренняя процедура.

Это дает возможность компактной и гораздо более надежный источник:

program trapezoidZ 
    implicit none 

    ! main program global variables and constants here. 

    call main 
contains 
    subroutine main 
    real :: u, integral 
    integer :: i 
    integer, parameter :: n = 10 
    ! delete declaration of trapezoid_integration and f. 

    integral = trapezoid_integration(my_f, 0.2, 3.0) 
    write (*,*) '#trapezoidal integration = ',integral 
    end subroutine main 

    function my_f(u) 
    real :: my_f 
    real, intent(in) :: u 

    my_f = (u**4)*EXP(u)/((EXP(u)-1.0)**2) 
    end function my_f 

    function trapezoid_integration(f, n, start_val, end_val) 
    ! delete declaration of integrand (assuming you have it). 
    procedure(my_f) :: f 
    ... 
    end function trapezoid_integration 

    function integrand(f, x) result (value) 
    ... 
    end function integrand 
end program trapezoidZ 
+0

В этом коде были небольшие ошибки. Я поставил окончательную версию в исходном сообщении. – user1543042

1

Пункт 12.6.4.4 проекта стандарта 2008 года, что я должен передать состояния:

A statement function shall not be supplied as an actual argument.

так что я думайте, что вы не можете делать то, что хотите, в том, как вы хотите это сделать. Интересно, что рассказал ваш компилятор, когда вы пытались скомпилировать код выше. Когда я исправил несоответствие между function trapezoid_integration и end subroutine trapezoid_integration в вашем посте мой компилятор (недавнее издание gfortran) жаловался, указывая на использование f в вызове trapezoid_integration:

Error: Statement function 'f' at (1) is not allowed as an actual argument

Он жаловался несколько других вещей тоже. Он мог бы указать, но не сделал, что функции заявления были устаревшими со времени 1990 года.

Существует множество способов исправить вашу программу, одна из которых заключается в том, чтобы сделать функцию интегрированной внутренней, то есть объявить ее внутри раздела contains в рамках программы. Фактически, я бы содержал все функции, которые вы показали внутри такого раздела в программе. Когда вы написали код, две процедуры trapezoid_integration и integrand являются внешними и компилятор не может проверить свои интерфейсы при их вызове. Перепишите f как функцию и вставьте contains, где у вас есть end program, и переместите end program в конец исходного файла, затем уберите оставшиеся ошибки.