пользователей: 30398
предметов: 12406
вопросов: 234839
Конспект-online
РЕГИСТРАЦИЯ ЭКСКУРСИЯ


19. Язык программирования Fortran. Функции и подпрограммы: описание, реализация. Внутренние, статические и автоматические переменные. Управление работой подпрограмм. Фактические и формальные параметры. Механизмы передачи параметров. Модули. Зоны видимости в модуле. Функции и подпрограммы как параметры. Перегрузка функций и подпрограмм. Рекурсивные функции и процедуры. Примеры.

1.Функции и подпрограммы: описание, реализация.

На функцию ссылаются в выражении, и она возвращает величину, которая используется при вычислении этого выражения. Существует три вида функций:

Встроенные функции

Внешние функции

Функции-операторы

Ссылка на функцию может появиться в арифметическом или логическом выражении. Когда выполняется ссылка на функцию, функция вызывается, а величина результата используется как операнд в выражении, которое содержит ссылку на функцию. Форма ссылки на функцию следующая:

переменная = имя-функции ([пар[,пар]...])

Имя-функции - это определенное пользователем имя внешней или встроенной функции или функции-оператора.

пар - это фактический параметр.

После основного текста программы расположен оператор contains (содержит, вмещает), означающий, что далее будет описана функция, используемая в текущей программе.

Функция, объявленная внутри программы после оператора contains, называется внутренней функцией.

Для вызова внутренней функции используется следующая схема:

тип function имя_функции (формальные параметры)

типы формальных параметров

операторы описания

исполняемые операторы

имя_функции=вычисленное значение

end function имя_функции

Пример:

program understanding_function

real, parameter :: pi=3.1415926

real x, dx, s

x=pi/8; dx=0.01

s=f(x+dx)/f(x-dx)+f(x)

write(*,"(A,f5.2)") "Result..." ,s

contains

real function f(xt)

real xt

f=(sin(xt)+cos(xt))/(xt+exp(xt))

end function f end

Аргументы, используемые при описании функции, носят название формальных параметров. Аргументы, которые используются при вызове функции, называются фактическими параметрами.

Пример (функция без аргументов):

program funct

write(*,*) Pi(), Pi()/2

contains

real function Pi()

  Pi=3.1415926

end function Pi

end

Подпрограммы.

Кроме функций, существует второй вид процедур - подпрограммы.

Если функция возвращает вычисленное значение, то подпрограммы позволяют выполнять ряд определенных действий, например осуществлять специальные операции ввода-вывода, обрабатывать массивы и др.

Подпрограмма записывается отдельно от основной программы, после оператора contains.

Чтобы создать подпрограмму, применяется следующая схема:

subroutine имя_подпрограммы (формальные параметры)

типы формальных параметров

операторы описания

исполняемые операторы

end subroutine имя_подпрограммы

Вызов подпрограммы происходит при помощи оператора call.

call имя_подпрограммы(фактические параметры)

Пример. Подпрограмма, выводящая сообщение об отношении двух чисел.

program ratio

integer а, b

call show(90,23)

call show(50,50)

contains

subroutine show(a, b)

integer а,b

if (a<b) then

write(*,100) a," is smaller than ", b

elseif (a>b) then

write(*,100) a," is bigger than ", b else

write(*,100) a, " is equal ", b

end if

100 format (i4,A,i4)

end subroutine show

end

2. Внутренние, статические и автоматические переменные.

Между операторами function и end function, subroutine и end subroutine находятся операторы, выполняющие определенные действия. Очень часто эти операторы содержат дополнительные, вспомогательные переменные.

Чтобы использовать такие переменные в процедурах, их следует объявить

сразу после описания формальных параметров:

real function T(x) real x            ! формальный параметр

integer k                                    ! дополнительные перем.

real :: sum=0

do k=1,100

sum=sum+cos(k*x)/k

end do

T=sum

end function T end

Название "внутренние переменные" не случайно. Такие переменные доступны только в "своей", "родной" функции и недоступны в основном тексте программы и других подпрограммах и функциях.

При этом переменные, описанные после оператора program, доступны как в основной программе, так и в процедурах, описанных после оператора contains.

Если имена переменных основной программы совпадают с именами переменных во внутренних процедурах, то эти переменные будут совершенно разными!

B следующем примере переменные res, описанные в основной программе и подпрограмме, – разные переменные:

program prog

logical :: res=.TRUE.   !переменная, доступная в основном тексте

call show()

write(*,*) "program res = ", res

contains

subroutine show()

logical :: res=.FALSE. !внутренняя переменная, доступна в show

write(*,*) "subroutine res = ", res

end subroutine show

end

По умолчанию все переменные, описанные в процедурах, являются статическими.

Это значит, что внутренние переменные, описанные внутри процедуры, создаются на этапе компиляции и существуют на всем протяжении работы программы.

program stat

write(*,100)       "F1=",  F1(),    "F2=",  F2()

write(*,100)       "F1=",  F1(),    "F2=",  F2()

write(*,100)       "F1=",  F1(),    "F2=",  F2()

100 format (2(А,i2))

contains

integer function F1() integer :: i=0

i = i + 5

F1=i

end function F1

integer function F2() integer i

i=0

i=i+5

F2=i

end function F2

end

B функциях F1() и F2() переменная i является статической.

Однако в функции F1() эта переменная инициализирована, т. e. на этапе компиляции ей присваивается начальное нулевое значение.

Поэтому переменная i содержит нуль только при первом обращении к функции, в последующих вызовах это значение увеличивается на 5.

Bo второй функции, F2(), переменной i присваивается нулевое значение при каждом обращении к функции и увеличение на 5 не происходит.

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

Следует заметить, что по умолчанию все статические переменные имеют атрибут save (сохранить). Наряду с атрибутом save существует также атрибут static (статический), который эквивалентен атрибуту save и указывает, что переменные сохраняют свои значения после работы процедуры.

B следующем примере переменным a и b явно присвоены атрибуты save и static:

real, save :: а

logical, static :: b

B противоположность статическим переменным существуют автоматические переменные. Для таких переменных память отводится не на этапе компиляции, а при каждом обращении к процедуре при выполнении программы.

При вызове процедуры автоматические переменные создаются и размещаются в стеке (временной памяти) и по завершении работы процедуры из стека удаляются.

Чтобы объявить переменные автоматическими, используется атрибут или оператор automatic:

integer, automatic :: a,b,c

automatic integer a,b,c

B последнем случае атрибут automatic будет присваиваться неявно остальным переменным, описанным в процедуре.

Автоматические переменные не допускают инициализации, так как создаются заново при каждом вызове процедуры!

Резюме:

Статическим переменным, имеющим атрибуты save или static, память отводится на этапе компиляции. Переменные, которые инициализированы, всегда статические.

Автоматическим переменным, имеющим атрибут automatic, память отводится автоматически программой (без участия программиста) в специальной области памяти - стеке и освобождается после окончания работы процедуры.

Наконец, динамическим переменным, с атрибутом allocatable, память отводится во время работы программы или процедуры и полностью может контролироваться программистом при помощи операторов allocate и deallocate.

3. Управление работой подпрограмм.

Чтобы функция могла обработать исключительную ситуацию, следует воспользоваться оператором return (возврат), который прекращает выполнение функции и возвращает управление вызывающей программе или процедуре

program see_error

write(*,*) "F(1.0) = ", F(1.0)

write(*,*) ''F(2.0) = ", F(2.0)

contains

real function F(xt) real xt

if (abs(xt)<1e-30) then

F = 0.0

return

end if

F = 1.0/(xt-1.0)

end function F

end

Для создания более универсальных процедур можно оформить некоторые формальные параметры дополнительными, что дает определенную гибкость при создании процедур. Например, в следующем примере, если требуется, то можно выводить последовательность целых чисел с определенным шагом step.

program option_param

call line(1,10, 2)

contains

  subroutine line(x1, xn, step) integer x,x1,xn,dx

  integer, optional :: step

  if (present(step)) then dx=step else dx=1

  end if

  do x=x1,xn,dx

  write(*,"(i4,4)") x

  end do

  end subroutine line

end

B подпрограмме формальный параметр step является необязательным и поэтому объявлен с атрибутом optional (дополнительный).

Чтобы определить, используется ли при вызове процедуры необязательный параметр или нет, вызывается функция present (присутствие).

B конструкции if выполняется проверка: если вызов подпрограммы происходит с необязательным параметром, то функция present возвращает значение .TRUE. и dx= step, иначе результат .FALSE. и dx=1.

Таким образом, если необходимо вывести последовательность натуральных чисел, то можно вызвать подпрограмму с двумя обязательными параметрами, указывающими первое и последнее число последовательности, call line(1,10)

Подпрограмму можно вызвать также с дополнительным необязательным параметром step, указывающим на шаг последовательности, call line(1,10,2)

4.Внешние процедуры

Внешними называются процедуры, описанные отдельно от основного текста программы:

program prog

integer res

call ReadResult(res) call PrintResult(res)

contains

subroutine ReadResult(а)          integer, intent(out) :: а

write(*,"(A,X)") "Enter value = "; read(*,*) a

end subroutine ReadResult

end

subroutine PrintResult(a) integer, intent (in) :: a

write(*,*) "Result = ",a**2

end subroutine PrintResult

Внешние процедуры могут находиться в одном файле с основной программой, в других файлах, библиотеках (lib-файлы), динамически подключаемых библиотеках (dll-файлы).

Внутренние процедуры не могут иметь внутренних процедур, внешние процедуры могут иметь внутренние процедуры.

Переменные, описанные во внешних процедурах, недоступны в основной программе. Переменные, описанные в основной программе, недоступны во внешних процедурах.

Внутреннюю процедуру нельзя передавать как параметр в другую процедуру, внешнюю можно.

Внутренние процедуры имеют явно заданный интерфейс, для внешних следует указывать явно, используя оператор interface (интерфейс):

если описана функция norm, вычисляющая длину вектора, то для того чтобы компилятор смог разобраться, что тип возвращаемого значения вещественное число (а не целое, на что указывает имя norm), в главной программе после оператора program используется оператор interface следующего содержания:

  interface тип имя_функции(формальные параметры)

  тип формальных параметров

конец описания функции

end interface

program vector

interface

real function norm(v) real, intent (in) :: v(3)

end function norm

end interface

real v(3) v=(/2,6,3/)

write(*,*) " Vector ",v

write(*,*) " Norm = ",norm(v)

end

real function norm(v) real v(3)

norm=sqrt(v(1)**2+v(2)**2+v(3)**2)

end function norm

Внешние подпрограммы можно размещать в отдельных файлах, а затем добавлять в проект.

Кроме того, разработанные процедуры можно откомпилировать отдельно и оформить в библиотеки.

5.Рекурсивные функции

Чтобы объявить процедуру рекурсивной, используется ключевое слово recursive.

Пример: программа печатает числа в обратном порядке. При этом рекурсивная подпрограмма оформлена как внутренняя.

program recurse

  call info(5)

  contains

  recursive subroutine info(k)

              if (k==0) then return

                            else

              write(*,'(А,i1)’) " k = ", k;

              call info(k-1)

  end subroutine info

end

B некоторых случаях использование рекурсии позволяет легко реализовать вычислительный алгоритм.

Одним из таких алгоритмов является вычисление определителя.

program determinant

integer, parameter :: M=10 integer a(M,M)

  write(*,*) "Enter matrix rows..."

  do i=1,M read(*,*) a(i,1:M) end do

  kk=det(a,M); write(*,*) "Determinant = ",kk

contains

  integer recursive function det(A,N) result(s)

  integer N, A(N,N), MR(N-1,N-1), k

  MR=0; s=0

              if (N==2) then S=A(1,1)*A(2,2)-A(1,2)*A(2,1)

                            else

                          do k=1,N

                                      MR(1:k-1,1:N-1)=A(1:k-1,2:N)

                                      MR(k:N-1,1:N-1)=A(k+1:N,2:N)

                                      s=(-1)**(к+1)*A(k,1)*det(MR,N-1)+s

                          end do

              end if

  end function det

end


10.06.2015; 08:27
хиты: 6226
рейтинг:+2
Точные науки
информатика
для добавления комментариев необходимо авторизироваться.
  Copyright © 2013-2024. All Rights Reserved. помощь