TW-CAD
    Что такое TestWard
    Технология
    Заказать тест
    Регистрация
    FAQ
    Статьи
  Проектирование
    Информация
    Вирт. лаборатория
  Учебный процесс
    1-й курс
      Лекции
      Ликбез
      Сессия
    5-й курс
      Литература
      Практикум
      Сессия
    Консультации
  Информация
    Как с нами связатся
    О нас

 

 

 

Программирование сложных задач

Программирование сложных задач

 

Термины и Принятые сокращения

  1. Программа состоит из Программных единиц (ПЕ), ПЕ – наименьшая часть текста решения задачи, которую можно оформить как самостоятельный текстовый файл, компилируемый, помещаемый в библиотеку
  2. Подпрограмма (ПП)  - это Функция или Процедура
  3. Функция решает подзадачу с единственным результатом, возвращая результат в формулу, где она упоминается
  4. Процедура решает подзадачу с любым количеством результатов
  5. Модуль содержит описания глобальных объектов и модульных ПП для их обработки
  6. Интерфейс или шаблон для вызова ПП указывает вид ПП и ее имя, а также содержит перечень и описания формальных параметров
  7. Формальные параметры – это объекты вызываемой подпрограммы, их пишут в заголовке ПП
  8. Фактические параметры (аргументы) – это объекты вызывающей программы, их перечисляют при вызове ПП
  9. Данные передают в вызываемую подпрограмму, сопоставляя аргументы формальным параметрам
  10. Результаты возвращают из процедуры, сопоставляя формальные параметры аргументам
  11. Ассоциирование (присоединение) объектов носителя в область видимости тех программ, которые в нее вложены
  12. Ассоциирование (присоединение) глобальных объектов Модуля в область видимости тех программ, где модуль используется
  13. Область видимости объекта – это одна или много программ, где над объектом можно выполнять действия
  14. Возможность реализации принципа инкапсуляции – это основное предназначение модуля

 

Аспекты сложности задачи

     Сложность имеет много аспектов: размер программы, организация данных и интерфейсов, память и быстродействие, точность и т.д. Аспекта “большая программа” коснемся в теме “подпрограммы и функции”, аспекта организации данных - в теме “Типы данных“, новейших интерфейсов и объема памяти - в теме “Программирование для WINDOWS”.

    Во всех языках программирования имеются средства разделения задачи на подзадачи, но они несколько различаются

  • FORTRAN стандартные функции, функции Ф90-внутренние и внешние, процедуры Ф90-внутренние и внешние, а также модули –только в Ф90, причем модулям нет аналогов в других языках
  • PASCAL - стандартные функции, функции, процедуры
  • C- стандартные функции, подпрограммы, они же могут быть и функциями

Опыт программирования аккумулируется в библиотеках программ

  • наиболее трудоемкий сервис - это ввод-вывод, особенно вывод на экран - в DOS и WINDOWS - это низкоуровневая графика - расширенный арсенал отображения графической и текстовой информации на экране
  • в WINDOWS -это QuckWin - быстрый и безболезненный переход от отдельной программы в DOS к приложению в многооконной многозадачной среде WINDOWS с увеличением на 2 порядка объема доступной памяти и с более мощной графикой на виртуальном экране.
  • имеются внеязыковые библиотеки, например, так реализован ввод-вывод в C и PASCAL
  • имеются внеязыковые библиотеки поддержки ОС, например, WinApi для Windows.
  • имеются графические библиотеки, в том числе низкоуровневая графика для “C” и Фортран,  а также внеязыковая реалистическая графика OPENGL
  • имеется уникальная библиотека программ на Фортране IMSL – более 1000 численных методов, статистика, матричная алгебра (одинарная и двойная точность, в комплексной плоскости) – все эти программы – это обычным образом оформленные функции, процедуры, а также модули Ф90
  • имеется емкая библиотека программ на Фортране для IBM-PC фирмы COMPAQ
  • известны компилятор и библиотека программ на Фортране и “C ” для IBM-PC фирмы INTEL

 

Программы, подпрограммы, процедуры, функции и модули

 

Простые, например, учебные программы вовсе не требуют подпрограмм и модулей. Однако, если в программе более 50-100 операторов, то человек, теряя контроль над многими отдельными частями, путается. Чтобы исключить ошибки, задачу подразделяют на подзадачи, программируя их в виде функций и процедур (подпрограмм). Анализ решаемой задачи часто позволяет выделить в ней повторяющиеся подзадачи. Оформив такую подзадачу в виде подпрограммы с параметрами, можно ее многократно вызывать, варьируя параметры. Если все данные сложной задачи передавать только через параметры, то их становится слишком много. Альтернативный путь – заимствование данных у носителя или модуля – этот путь реализован в Ф90. Часто повторяются и функции, которые надо вычислять, - их тоже можно оформить в виде самосто­ятельных частей задачи. Нужны подпрограммы и при смешанном программировании на разных языках, ска­жем "С" и Фортран. Согласно принципу независимости подпрограмм каждую из них можно компилировать самостоятельно, а результат компиляции поместить в  библиотеку. На эту личную библиотеку затем ссылаются при ко­мпоновке наряду со стандартной библиотекой Фортрана. Принцип независимости программ означает независимость обозначений и описаний, что позволяет в каждой решаемой задачке, оформляемой как внешняя программа, полностью игнорировать обозначения других программ. Наоборот, чтобы сохранить единый стиль и обозначения при проектировании сложной программы, общие описания и определения выносят в отдельный модуль в Фортране (include в языке “C”). Модули, появившиеся в Ф90, куда более мощное средство, чем include.

Чтобы лучше понять отличия в оформлении программ разных видов

·         в учебном проекте реальная задача подразделяется на подзадачи

·         рассматриваются правила написания программ и вспомогательных операторов

 

Учебный проект

Для того чтобы войти в проблематику решим простенькую, но вполне реальную задачу. На примере рассматриваются 3 основные вида программ.

Задача. Гражданам предлагаются разновидности Лото, Спортлото, в которых на карточке из многих номеров предлагается отметить несколько. В случае угаданных цифр сулят выигрыш, тем больший, чем больше цифр предстоящего тиража угадано. Спрашивается, так ли велик шанс, выиграть? Шанс - это вероятностная величина P, обратная числу вариантов S заполнения карточки. Используем формулы

  • P = 1 / S    
  • S  =  n! / (m!(n-m)!)   -   число сочетаний из n по m 

Попробуем сначала написать более знакомую нам главную программу, задающую данные и печатающую ответы. Для двух наиболее популярных игр "5 из 36" и  "6 из 45" рассчитаем шанс сорвать самый крутой куш. Остальные менее значимые шансы оставим на самостоятельное программирование.

Главная программа. Каково число вариантов игр в лото "5 из 36" и "6 из 45"

Обратим внимание на то, что главная программа Loto_2_games сама ничего не будет вычислять, а будет пользоваться услугами процедуры, названной Loto. Две игры - два вызова процедуры Loto.

Процедура Loto.  Для того чтобы воспользоваться услугами процедуры Loto, - на это надо обратить особое внимание - главной программе совсем не надо знать, как внутри устроена подпрограмма. Что же надо знать?

Надо знать интерфейс

в нашем случае интерфейс ПП Loto

в каком виде оформлена ПП в виде процедуры или в виде функции?

-        подпрограмма в виде процедуры

как называется процедура ?

Loto

Сколько у нее входных данных (входных параметров - как в математике) и какого типа эти параметры?

-        целое nсколько клеток на карточке

-         целое m-сколько клеток надо заполнить на карточке

Сколько у нее выходных данных (выходных параметров) и какого типа эти параметры  ?

-        вещественное число - "вариантов заполнения карточки"

-         вещественное число - шанс (вероятность)

Если кто-то захочет рассчитать другую игру

  • Он не обязан знать, как внутри устроена ПП Loto
  • Но он должен знать перечисленные сведения, объединенные понятием интерфейс ПП
  • interface .. .. end interface – это новый составной неисполняемый оператор Ф-90, в котором дан шаблон вызова ПП
  • придерживаясь этого шаблона можно вызывать ПП и задавать параметры
  • варьируя параметры ПП Loto, можно рассчитать сколько угодно игр
  • расчеты производятся много раз, но запрограммированы они ровно один раз в ПП Loto

 

Program Loto_2_games    !   Программа  Loto  - расчет двух игр "5 из 36" и "6 из 45"

   real  S36,P36,  S45,P45

           interface

             Subroutine Loto ( m,n, S,P   ! определение подпрограммы  Loto

                 integer,intent(in) :: m, n   !  in - входные параметры
                 real,intent(out) ::
  S,P    !  out - выходные параметры

             end Subroutine Loto

         end interface

 open( 2, file='chance.txt' )

 call Loto ( 5,36,  S36,P36 )    !   вызов   подпрограммы  Loto - лото "5 из 36"

 write(2,1) 5 из 36’, S36, P36

 call Loto ( 6,45,  S45,P45 )     ! вызов   подпрограммы  Loto - лото "6 из 45"

 write(2,1) '6 из 45' , S45, P45'

    1 format(' игра ‘,a,’ число вариантов', g12.4, '  : шанс с вероятностью = ' , g12.4)

end

С учетом сделанных пояснений, процедура Loto может выглядеть так

Subroutine Loto ( m,n, S,P )     ! определение подпрограммы  Loto

   Integer,intent(in) :: m, n   !  in - входные параметры
     real,intent(out) ::
  S,P    !  out - выходные параметры

              interface

                 Function Factorial ( n )  ! определение  интерфейса подпрограммы-функции

                     integer,intent(in) :: n;     real*8 Factorial

                 end Function Factorial

              end interface

    S = Factorial (n) / (Factorial (m)* Factorial (n-m)) ! троекратный вызов подпрограммы-функции

    P = 1 / S

 End

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

Подпрограмма-функция Factoriial.

Для написания ПП Loto разработан и среди описаний ПП Loto записан интерфейс функции Factorial.

Надо знать интерфейс функции Factorial

в нашем случае

в каком виде оформлена подпрограмма в виде процедуры или в виде функции?

подпрограмма в виде функции, один ответ-это сама функция

как называется подпрограмма-функция

Factorial вещественное число удвоенной точности

Сколько у нее входных данных (в математике - аргументов) и какого типа эти параметры  ?

целое n - сколько клеток на карточке

 целое m - сколько клеток надо заполнить

Примечания:

·        ответ у любой функции ровно один – в нашем примере - это и есть значение функции Factorial, которое после завершения ПП будет непосредственно использовано в формуле вызывающей программы

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

самое большое целое число integer порядка 1.e10 

самое большое вещественное число real порядка 1.е38  

самое большое вещественное число двойной точности real*8 порядка 1.е308

·        текст внутри оператора interface .. .. end interface, взятый из  ПП Loto может служить заготовкой для ПП-функции Factorial

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

·        по форме вызов нашей собственной функции Factorial ничем не отличается от вызова стандартных функций

 

ПП-функция Factorial для вычисления факториала  n! = 1*2*3*.. *n может выглядеть так

Function Factorial ( n )  ! заголовок  подпрограммы-функции

   real*8 Factorial   ! тип результата  двойной точности

  integer,intent(in) :: n  ! единственный входной параметр

   integer k

     Factorial = 1

     if ( n = = 0  ) return     !  из математики известен особый случай: 0!=1

     do k=1,n

        Factorial = Factorial *k

     enddo

 end Function Factorial

Примечания:

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

·  из математики известен особый случай 0!=1  - в этом случае оператором return досрочно  завершается выполнение ПП с возвращением в вызывающую программу

·  функция Factorial  вызывается из процедуры Loto, но нет никаких препятствий, чтобы ее вызвали и в любой другой задаче, где надо вычислять факториал;

·  чтоб сделать функцию Factorial общедоступной
            надо ее скомпилировать и поместить в доступную библиотеку;
            другой вариант - в проект подключить текст  этой программы

·  чтоб собрать готовую программу из

          главной программы Loto_2_games,   процедуры Loto  и  ПП-функции  Factorial надо
                  либо сложить все тексты ПЕ стопочкой, не важно в каком порядке,
                  либо каждую ПЕ оформить в виде самостоятельного текста и включить в проект

Программные единицы и вспомогательные операторы

Текст решения сложной задачи можно разделить на части. В одной части текста можно разместить одну или несколько программных единиц (ПЕ). ПЕ – это минимально допустимая часть текста решения сложной задачи, которую можно оформить как самостоятельный текстовый файл, компилируемый, помещаемый в библиотеку. Все остальные операторы неисполняемые и исполняемые размещают внутри ПЕ. Используя компоновщик, из ПЕ можно собрать готовую к исполнению программу. ПЕ - это главная программа, внешняя функция, внешняя процедура или Модуль. Главная программа - единственная в задаче.

ПЕ относят к особому виду составных операторов:

·       Program имяРек.. .. end Program имяРек - главная программа
с нее начинается решение задачи, а по end - нормально завершается задача и текст главной программы

·       Subroutine имяРек.. .. end Subroutine имяРек - это ПП-процедура

 она решает какую-либо подзадачу, по end - нормально завершается подзадача и текст процедуры

·       Function имяРек.. .. end Function имяРекэто ПП-функция

она вычисляет какую-либо функцию, по end нормально завершается вычисление функции и текст ПП-функции

·      Module имяРек .. .. end Module имяРек  - это модуль

в модуле нет действий, поэтому по end Module имяРек  оканчивается только текст модуля,

в модуле аккумулируются интерфейсы, а также общедоступные данные и ПП для их обработки

 

Обе вместе Subroutine и Function будем называть подпрограммами (ПП).

К числу вспомогательных операторов и атрибутов относят:

End*

оператор

конец ПЕ

нормальное завершение
задачи нормальное завершение подзадачи
и/или конец текста ПЕ

Stop

оператор

досрочное завершение задачи в любой ПЕ

Return

оператор

досрочное завершение подзадачи (ПП),
 но не всей задачи

Pause

оператор

пауза до нажатия Enter

Interface

.. ..

end Interface

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

явное описание интерфейса или шаблона для вызова ПП на Фортране или на другом языке

Include**

Оператор среди описаний

включить описания и определения в текст ПЕ

Use имяРек

Оператор после заголовка ПЕ

использовать модуль

Call имяРек(..A)

оператор

Вызвать процедуру с аргументами A

имяРек(..A)

Упоминание
в формуле

Вызвать функцию с аргументами A
в формуле вызывающей программы

intent(in)

intent(out)

intent(inout)

Атрибут или оператор в ПП

Входной      intent -вид связи параметра ПП

выходной

входной- выходной

External***

Атрибут или оператор

внешние функции, используемые как аргументы при вызове ПП

intrinsic***

Атрибут или оператор

внутренние функции Ф90, используемые как аргументы ПП

Optional

Атрибут или оператор в ПП

атрибут необязательного параметра

Public/private

Атрибут или оператор в модуле

глобальные/локальные объекты модуля

common**

оператор

Общие блоки памяти

(*) Имя программы и вид программы можно повторить в операторе end;
     для модуля, модульных и внутренних программ – это делать обязательно

(**) оператор, объявленный устаревшим в Ф90

(***) имена подпрограмм или функций, передаваемых как аргументы

 

Классификация ПЕ в Фортран-90

Будем формально придерживаться двух способов классификации

  • по видам программ, с указанным ключевым словом в заголовке
  • по месту относительно других ПЕ

 

Фортран-90: Классификация программ по видам

К особому виду составных операторов относят программные единицы (ПЕ), как-то: 

 Program  Subroutine  Function  Module.

Обе вместе Subroutine и Function будем называть подпрограммами (ПП).

По форме написания и назначению в Фортране различают следующие виды программ: 

  • Встроенная или стандартная функция, например, sin(x) – определена стандартом языка Фортран-90
  • Программная единица (ПЕ) – начинается с заголовка Program Subroutine Function Module и заканчивается end с указанием вида и имени ПЕ,
    например
    Module M .. .. end Module M
  • ПЕ главная программа - заголовок program – в каждой задаче единственная
  • ПЕ - подпрограмма (ПП) – процедура или функция
  • ПП – с заголовком Subroutine будем называть процедурой.
  • ПП –  с заголовком  Function будем называть ПП-функцией.
  • Операторная функция не образует самостоятельной ПЕ и описывается
    простым оператором описания вида F(x,y..)=выражение
  • Интерфейс или шаблон ПП  - составной оператор описания, не образующий самостоятельную ПЕ 
      
    Interface .. .. end Interface
  • ПЕ модуль – заголовок module – только в Ф90

Способ применения различается для разных видов программ

  • Главную программу Program загружают средствами операционной системы
  • Стандартную функцию упоминают в выражении имяF(список аргументов)
  • Вызов ПП-функции Function по форме ничем не отличается от вызова стандартных функций
  • процедуру Subroutine вызывают специальным оператором CALL имяS(список аргументов)
  • модули используют в операторе USE имяM, а не вызывают (в них нет действий),
    это дает возможность присоединить и сделать видимыми во внешней ПЕ глобальные (
    public) объекты модуля
  • вызов ПП может сопровождаться передачей предусмотренных параметров
  • для внутренней ПП к ее собственным описаниям присоединяются и становятся видимыми объекты программы-носителя с другими именами
  • для модульной ПП к ее собственным описаниям присоединяются и становятся видимыми объекты модуля-носителя с другими именами

 

Начинающему программисту не просто сделать обоснованный выбор, оформляя программу в надлежащем виде. Примеры четырех вариантов оформления одной и той же задачи вычисления факториала см. в “учебном проекте”, в примере 4.1, 4.2, 4.3, 4.4.

 

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

·       по горизонтали - сколько исполняемых операторов в программе по принципу  "0" "1" "много"

·       по вертикали - сколько результатов (выходов), возвращаемых в вызывающую ПЕ, считая подпрограмму черным ящиком, у которого при вызове                  ·       "много входов - много выходов"

·       "много входов - 1 выход"

·       "ни входов - ни выходов"

 

Используя таблицу, проведем сравнительную классификацию программы по видам. В правую колонку "много" попали три основных вида ПЕ. Только многи­ми операторами можно запрограммировать сложную задачу, разделенную на подзадачи в виде ПП.

По разным причинам в колонке “0” , то есть без исполняемых операторов, сосредоточено 4 представителя

·        Интерфейсы функций и процедур, которые в Ф90 не образуют самостоятельный вид ПЕ, а числятся прямо среди описаний вызывающей ПЕ; либо опосредованно - среди описаний в используемых модулях

  • стандартные функции, реализованные, скорее всего не на Фортране
  • Модуль, являющийся самостоятельным видом ПЕ, не содержащим выполняемых операторов и состоящим
    - из интерфейсов вызываемых ПП
    - из описаний локализованных в модуле
    private-объектов
    - из описаний общедоступных
    public-объектов
    - из модульных ПП для обработки
    public-объектов

Операторная функция состоит из единственной строчки ИМЯ(..v) = e , которая содержит формулу, по форме напоминающей оператор присваивания. Ее можно считать как исполняемым оператором, так и определением. Числится она среди описаний, и пользуется описаниями программы, в которой упоминается.

ПЕ вызывают по цепочке, начинающейся с вызова Prorgram  из DOS или WINDOWS. ПП-функцию Function и ПП Subroutine вызывают по-разному:

  • ПП-функцию упоминают в формуле, куда она возвращает вычисленное значение
  • ПП-процедуру вызывают специальным оператором   call  ИМЯ(..v)

Часто по своему усмотрению программист может оформить ПП и как Function и как Subroutine. Умение удачно разделить задачу на подзадачи и выбрать подходящий вид ПЕ приходит с опытом. При большом числе входов/выходов удобнее передавать данные не через параметры, а через посредство заимствования объектов. Передача объектов через общие блоки памяти, описываемые в операторе  common, относят к числу устаревающих конструкций.

 В центральной строке "1" сосредоточены все 4 вида функций, каждую из которых независимо от способа определения, можно вызывать единообразно, просто упоминая в формуле вызывающей программы. Способ определения зависит от числа исполняемых операторов, написанных на Фортране. Для  стандартной и интерфейсной функции (ИФ) исполняемых операторов просто нет. Точнее говоря, они написаны в другом месте:

  • стандартная функция, скорее всего, на Ассемблере, но не на Фортране
  • интерфейсная функция, возможно, например на “С”, а не на Фортране
  • интерфейсная функция, возможно, например, и на Фортране, но в другом месте, например, кем-то, написана, скомпилирована и помещена в библиотеку, к примеру, IMSL

Операторная функция (ОФ) уникальна ввиду наличия единственного исполняемого/описательного оператора. Говоря точнее, ОФ - это не самостоятельная ПЕ, а  конструктивное определение, действующее только в той ПЕ, чьими обозначе­ниями она пользуется. Только внутри этой ПЕ и можно вызывать такую функцию, так как выражение e, зависящее от переменных ..v записано в терминах этой ПЕ. В другой ПЕ оно не действует, так как обозначения разных ПЕ независимы. В выражение e помимо параметров могут входить и другие переменные  вызывающей программы - они подставляются по значению на момент вызова ОФ. ПП вида Function ИМЯ (..P)  относится к основному виду и является функцией, оформленной в виде самостоятельной ПЕ, содержащей любое число операторов. Внутри этой ПП ИМЯ используется как переменная, которой присваивается значение функции, например, в операторе присваивания ИМЯ=e , здесь e - выражение. ИМЯ – одновременно и название функции, и переменная, отнесенная к одному из 5 базовых типов данных или производному типу данных (только в Ф90). По размерности и типу в Ф90 для функции возможны разные случаи

1.      функция может быть скаляром, как раньше в Ф77 (тогда это был единственный вариант)

2.      функция может быть массивоподобной, то есть быть вектором или многомерной таблицей

3.     функция может быть элементной, будучи определена и как скаляр, и как массивоподобная функция; в зависимости от размерности аргументов станет или скаляром или вектором

4.      функция может перенимать тип у аргументов

Так как системы обозначений разных ПЕ независимы, то в вызывающей программе либо в модуле

·       в случае 1 обязательно надо описать хотя бы тип функции

·        в случаях 2,3,4 обязательно надо описать явный интерфейс, чтобы использовать механизм перегрузки

Интерфейсы функций и интерфейсы процедур особенно важны при смешанном программировании на “С” и Фортране.

Интерфейсы функций и интерфейсы процедур поставляются в составе фирменных пакетов, одинаково доступных и в “С” и в Фортране.

Тексты интерфейсных функций и процедур низкоуровневой графики.

·   подключают оператором include ' *.fi ' в начале ПЕ для ДОС

·   используя модуль use MSFLIB  в Windows

Богатая, ориентированная на Windows библиотека “С”, может быть использована в Фортране, если написать собственные интерфейсы, что требует понимания Фортрана и в какой-то мере “С”. Так можно применить и функции из dll, реализующих саму среду Windows. Применение функций из динамически связываемых библиотек dll требует их предварительной регистрации. Процедура на “С” истолковывается как Function либо Subroutine с соответственным вызовом. Вызов стандартных функций так естественен, что кое-кто даже не догадывается, что за этим порой стоит программа, для повышения эффектив­ности написанная на машинно-ориентированном Ассемблере.

В нижней строке "0" показаны два черных ящика без передачи данных через параметры:

  •  Program -  начинает и нормально завершает решение задачи (по ее end);
  • Module не содержит выполняемых операторов, но в нем упакованы данные вместе с ПП для их обработки

 

Фортран-90: Классификация программ по местоположению

Внешние ПЕ могут следовать друг за другом в тексте или составлять самостоятельный текст. Внутренние ПП вкладываются во внешние ПЕ вслед за словом “contains”. Внутренние ПП также вкладываются аналогично в модульные ПП. Модульные ПП аналогично вкладываются в модуль. Сам модуль не содержит исполняемых операторов, но содержит описания и, возможно, модульные ПП. В модульных ПП исполняемые операторы есть.

По местоположению относительно других ПЕ различают

  • внешняя ПЕ – это программа вида Program Subroutine Function, которая записана в виде текста, расположенного обязательно не внутри другой ПЕ. Внешние ПЕ оформляются
          либо в виде самостоятельного текстового файла
          либо следуют подряд по тексту наравне с другими внешними ПЕ в общем текстовом файле
  • модуль – это самостоятельная ПЕ без исполняемых операторов, но, возможно, с модульными ПП
  • модульные ПП находятся внутри модуля после CONTAINS перед END
  • внутренние ПП находятся внутри какой-либо ПЕ-носителя после CONTAINS перед END ПЕ-носителя
  • носителем по отношению к внутренним ПП  могут быть ПЕ вида Program, внешняя поцедура Subroutine, внешняя ПП-функция Function, модульная ПП

  

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

 

 

Вид программы

Структура программы

Примечания

1

Главная

Prorgram ИмяPr ! нет параметров

.. ..

CONTAINS

пачка Внутренних ПП

end

Единственная в задаче.

Имеет свои локальные объекты и использует публичные объекты используемых модулей, предоставляя их внутренним ПЕ
самостоятельный вид ПЕ

2

Внешняя процедура

Subroutine ИмяS(параметры)

.. ..

CONTAINS

пачка Внутренних подпрограмм

end Subroutine ИмяS

Не внутри другой ПЕ.

 Имеет свои локальные объекты и использует публичные объекты используемых модулей, предоставляя их внутренним ПП
самостоятельный вид ПЕ

3

Внешняя

функция

Function ИмяF(параметры)

Тип ИмяF

 .. ..  в том числе ИмяF= формула  

CONTAINS

пачка Внутренних подпрограмм

end Function ИмяF

Не внутри другой ПЕ.

Имеет свои локальные обозначения и использует публичные объекты используемых модулей, предоставляя их внутренним ПП
самостоятельный вид ПЕ

 

4

Встроенная

 функция

Вызывается в выражении

t =Sin(X+0.5) +2.3

функция определена в языке

 

5,6

Модульная ПП -процедура или функция

После 1-го  CONTAINS модуля

 Subroutine или Function

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

Внутри модуля

 

 

7,8

Внутренняя ПП -процедура или функция

После  единственного CONTAINS главной, внешней или модульной ПЕ Subroutine или Function

Видит объекты своей внешней ПЕ и имеет свои локальные объекты
Внутри внешней или модульной ПП

9

Операторная функция

Dist(x1,y1, x2,y2) = sqrt((x1-x2)**2+( y1-y2)**2)

Dr=dist( x,y, 5.,1.56)

Видима только внутри ПЕ, где определена. Упоминается в выражениях среди действий.
среди описаний какой-либо ПЕ

10

Модуль

Module ИмяM ! нет параметров

 Описания
contains
   модульные ПЕ
   .. ..

end Module ИмяM

Публичные объекты свои и используемых модулей предоставляет внешним ПЕ. Имеются свои локальные объекты, предоставляемые Модульным ПП
самостоятельный вид ПЕ

11

Явные интерфейсы или шаблоны для вызова ПЕ

Interface

 Subroutine ИмяS(параметры)

    только описания параметров

  end Subroutine ИмяS

End Interface

указываются среди описаний в модуле или в вызывающей ПЕ

описания параметров – локальны в интерфейсе
среди описаний какой-либо ПЕ

Примечание: вид программы и имя программы в операторе end указывать желательно, 

                    а для модульных и внутренних программ - обязательно.

 

Фортран-77: Виды программ

Возможности Ф77 были скромнее, и в нем различали лишь следующие виды программ: 

  • главная программа
  • самостоятельная ПП - это процедура или функция со своими обозначениями
  • несамостоятельная - операторная функция – единственная строка F(x,y,..)=формула  среди описаний программы
  • от MS в расширение Фортран-77 - интерфейсы ПП

    В Ф77  нет деления на внешние и внутренние программы: ПЕ друг у друга никаких объектов не заимствуют, и полностью независимы друг от друга по обозначениям объектов. Они могут передавать данные через параметры или иметь общие блоки памяти, упомянутые в описаниях. В заключение дадим сводную таблицу всех видов ПЕ Ф77

1

Главная программа

Prorgram ИмяPr

.. ..

end

ГП - единственная в задаче,

Имеет свои уникальные объекты
Общие блоки памяти

2

ПП-Процедура

Subroutine ИмяS(параметры)

.. ..

end

Свои уникальные объекты
Общие блоки памяти

3

ПП-Функция

Function ИмяF(параметры)

Тип ИмяF

 .. ..  в том числе ИмяF= формула 

 end

Свои уникальные объекты
Общие блоки памяти

4

Встроенная или стандартная функция

Упоминается в выражении

t =Sin(X+0.5) +2.3

Стандартная функция определена в языке

5

Операторная функция

F(x,y,..)= формула  среди описаний
Dist(x1,y1, x2,y2) = sqrt((x1-x2)**2+( y1-y2)**2)

 

Видима только внутри ПЕ, где определена. Упоминается в выражении среди действий

Dr=dist( x,y, 5.,1.5)

 

Механизм вызова процедур и функций,  передача данных через параметры и путем заимствования

Механизм вызова программ различается

·        главную программу загружают средствами операционной системы.

·        процедуру - вызывают, используя оператор   CALL Имя(..Аргументы) - после имени в скобках через запятую перечисляются аргументы или как их еще называют фактические параметры

·       любую функцию и стандартную, и нестандартную  вызывают, упомянув ее имя в формуле вызывающей программы

Имя(..Аргументы)  - после имени в скобках через запятую перечисляются аргументы

·        каждая из программ может вызывать все виды программ, кроме чужих внутренних подпрограмм; вызываемая подпрограмма в свою очередь может стать вызывающей для других подпрограмм, разрешается даже вызов самое себя, то есть рекурсия

·       модуль не вызывают, а используют с помощью   use Имя,  обязательно сразу после заголовка программы; один модуль может использовать другой модуль, но модулю никак нельзя использовать самого себя ни напрямую, ни через цепочку модулей.

Обмен данными между программами осуществляется одним из указанных ниже способов

  • сопоставляя аргументы вызывающей программы с параметрами вызываемой программы
  • делая видимыми объекты из модуля M при использовании его с помощью оператора Use M
  • делая видимыми локальные объекты внешней программы-носителя для всех  внутренних подпрограмм, помещенных после contains

Рассмотрим как данные кочуют из вызывающей программы в  вызываемую программу и обратно.

В Ф77 все ПЕ были полностью независимыми (как мы сказали бы в Ф90-внешними ПЕ). Каждая ПЕ имела свои собственные, независимые от других обозначения и описания объектов. Данные можно было передавать только двумя способами:

1.      -        через параметры, сопоставляя аргументы формальным параметрам

2.      -        через общие блоки памяти, как в “C

В Ф-90 обмен данными между программами стал более разнообразным, и данные теперь можно передавать:

1.      -        через параметры, сопоставляя аргументы формальным параметрам

2.      -        поименно заимствуя объекты для внутренних программ у внешней программы-носителя

3.      -        поименно заимствуя объекты у модуля для внешних программ и транзитом - для внутренних программ

4.      -        устаревший С-подобный способ - через общие блоки памяти

 

Передача данных через параметры

Этот способ применяется во всех языках программирования. Так делают и в стандартных программах.  Так же делают и в тех случаях, когда, варьируя небольшое количество параметров, можно легко настраивать свои ПП на выполнения тех или иных действий.

Фактические параметры являются объектами вызывающей программы. Фактические параметры перечисляются при вызове ПП после названия вызываемой подпрограммы.

Формальные параметры являются объектами  вызываемой программы. Формальные параметры указываются в заголовке ПП после ее названия. Формальные параметры нужны для понимания текста ПП, под них даже не отводится памяти. Например, если это массив, то в ПП передается адрес, где лежит этот массив в вызывающей ПЕ.

Формальные параметры по виду связи, описываемому с помощью атрибута Intent,  подразделяются на три вида,

·       Intent (in)  - входные параметры

·       Intent (out)  - выходные параметры

·       Intent (inout)  - входные- выходные или изменяющиеся параметры

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

Для процедуры сопоставление производится так

  • объекты вызывающей ПЕ в виде аргументов, поступают на вход ПП и становятся значениями сопоставленных им формальных параметров  вида in или inout для Subroutine
  • объекты вызываемой ПП, являющиеся результатами, поступают на выход ПП
    - формальные  параметры процедуры  
    Subroutine вида out или inout становятся значениями сопоставленных им фактических параметров

 

Вызывающая ПЕ   call  ИмяS(..A), 

где ..A-фактические параметры

              - объекты  вызывающей ПЕ

 

Туда
 
Aà P

Вызываемая ПП    SubroutineИмяS(..P)
где P -формальные параметры
      -
объекты вызываемой ПП

PàA Обратно

при вызове ПП
call  ИмяS(..A) передаем

аргументы (..A

   

 на вход ПП

аргументы становятся значениями формальных параметров (..P)

входные
    
in  AàP

  входные-выходные inout  AàP

Аргументы обрабатываются

исполняемыми

операторами

и

формируются результаты

 

 
 

Передаются через посредство формальных параметров


Inout
выходных входных
pàA


out 
выходных
pàA
 

При выходе из ПП

 результаты

становятся

значениями фактических параметров

 
   

сопоставляются попарно
A/P

Сопоставляются попарно

P/A

 

Для ПП-функции сопоставление производится так

  • объекты вызывающей ПЕ в виде аргументов, поступают на вход ПП и становятся значениями сопоставленных им формальных параметров вида in для Function
  • единственный результат, названный именем  ИмяF с выхода ПП подставляется непосредственно в формулу вызывающей ПП

 

 

Упоминается в формуле вызывающей ПЕ   ИмяF(..A), 

где ..A - фактические параметры

              - объекты  вызывающей ПЕ

 

 Туда  Aà P

Вызываемая ПП    Function ИмяF (..P)
где P -формальные параметры  - объекты вызываемой ПП

Только ИмяF обратно 

При вызове ПП
 ИмяF (..A) передаем

аргументы (..A

   

 на вход ПП

 

аргументы становятся значениями формальных параметров (..P)

есть только  входные 
 
in  AàP

 

 

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

обязательно вычисляют единственный

результат

ИмяF

 

результат передается

через 

  имя функции ИмяF

  

 

При выходе из ПП единственный результат подставляется в формулу вызывающей программы

сопоставляются попарно
A/P

передается по имени функции ИмяF

 

Сопоставление параметров выполняется по определенным правилам:

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

    - необязательные параметры, имеющие в  вызываемой программе атрибут optional, можно опустить при вызове
  • типы, вид связи и форма сопоставляемых объектов вызывающей и вызываемой программ должны быть попарно согласованными
  • используя механизм перегрузки с помощью задания кратного интерфейса, можно варьировать тип и количество параметров, сделать функции элементными
  • необязательные, ключевые и варьируемые по типу и форме параметры нестандартных ПП, массивоподобные функции допустимы только при наличии явного интерфейса
  • необязательные, ключевые и варьируемые по типу и форме параметры имеются и у стандартных ПП, их интерфейсы прописаны в стандартном модуле (use MSFLIB - для FPS 4.0)

 

Механизм вызова  Subroutine и Function  различаются:

1) по форме вызова
         процедуру вызывают специальным оператором call ИМЯ(..v),
         функцию вызывают, просто упоминая имя в формуле вызывающей программы ИМЯ(..v)

2) по количеству результатов
        для Function - единственный результат, совпадающий с именем функции
        для Subroutine - сколько угодно результатов

3) по виду связи входных параметров

         только intent(in) для Function 
         intent(in) и intent(inout) для Subroutine

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

        из Subroutine все результаты передаются через формальные параметры вида out и inout в сопоставленные им фактические параметры

5) Subroutine  может передавать результаты вне связи с параметрами, пользуясь механизмом заимствования

  • В процессе решения задачи вызывающей может стать любая ПЕ, выполняющаяся в данный момент, как это предусмотрено программой.

Механизм вызова ПП  Subroutine и Function  схожи в том, что

  • при входе в ПП
    выделяется память под автоматические массивы
    передаются данные из аргументов в сопоставленные им формальные параметры
  • ПП могут получать данные вне связи с параметрами, пользуясь механизмом заимствования
  • по end главной программы закрываются все файлы, освобождается память, и решение задачи заканчивается
  • по stop в ПЕ любого вида решение задачи заканчивается, как и по end главной программы, но на консоль дополнительно выдается сообщение о прекращении работы "program terminated"
  • по stop ‘текст’ на консоль дополнительно выводится текст’, например, stop ‘конец работы из-за ошибок’
  • по stop 1000 формируется  код завершения задачи, равный 1000  для передачи в операционную систему
  • по оператору pause задача приостанавливается до нажатия любой клавиши
  • по pauseтекст’  дополнительно на консоль выводится текст
  • end в процедуре завершает ее работу,
    освобождается память, выделенная под автоматические массивы,
    передаются данные из формальных параметров в аргументы, сопоставленные им
    процедура
    может возвращать результаты вне связи с параметрами, пользуясь механизмом заимствования
  • end в ПП-функции завершает ее работу,
     освобождается память, выделенная под автоматические массивы,
    через имя функции передается единственный результат и подставляется в формулу вызывающей программы
  • return досрочно завершает выполнение ПП и выполняет действия как по end соответствующего вида ПП

 Рекурсия, то есть вызов самое себя прямо или по цепочке

  • в Ф77 не разрешается
  • в Ф90 разрешается
  • ни в каком виде не разрешается по использованию модулей (через посредство use)

 

Область видимости объектов, механизм заимствования

Область видимости характеризует те объекты, над которыми можно выполнять действия в той или иной программе. В Ф77, где система обозначений каждой ПЕ была полностью независима от других ПЕ, область видимости - это просто все объекты этой ПЕ. Область видимости объектов такой ПЕ нарисуем, направив стрелку со стороны действий на объявленные объекты

 

В Ф-90 обмен данными между программами стал более разнообразным, так как данные можно теперь передавать:

·        через параметры, сопоставляя аргументы формальным параметрам

·        поименно заимствуя объекты у внешней программы-носителя для внутренних программ, похоже на Паскаль

·       поименно заимствуя объекты у модуля для внешних программ, нет аналога ни в “C” ни в Паскале

·        поименно заимствуя объекты у модуля транзитом через внешние программы - для внутренних программ

·       устаревший С-подобный способ - через общие блоки памяти по адресам внутри блока

 По этой причине область видимости расширилась и усложнилась, стали различать

  • локальные объекты, которые видимы только в ПЕ, где они описаны
  • глобальные объекты, которые видимы не только в ПЕ, где они описаны, но и во внутренних ПП
  • глобальные private-объекты, которые видимы только внутри модуля, где они описаны
  • глобальные public-объекты, которые видимы там, где модуль использован

 

Область видимости локальных объектов и глобальных объектов для программы-носителя

В Ф90 программой-носителем может быть

  • главная программа
  • внешняя процедура
  • внешняя функция
  • модуль
  • модульная процедура
  • модульная функция

Программа-носитель предоставляет свои объекты и делает их видимыми для всех подпрограмм вложенных в нее. Вложение производится в конец текста программы между операторами contains и end. Если вложений нет, то  contains опускают.

Программа имеет структуру и порядок следования операторов, представленные в таблице

 

Заголовок ПЕ на выбор:

·        PROGRAM    Имя

·        SUBROUTINE Имя(..P)

·        FUNCTION    Имя(..P)

·        MODULE      Имя

Определяет вид программы-носителя

главная программа – обязательно без параметров

Внешняя процедура либо модульная процедура *)

внешняя функция либо модульная функция *)

модуль– обязательно без параметров

..P список формальных параметров

! комментарии

Располагаются в любом месте программы

Use ИмяМ1

Æ видим глобальные public-объекты в модуле ИмяМ1
Æ доступны процедуры и функции из модуля ИмяМ1

+ применимы шаблоны из модуля ИмяМ1 для вызова ПП

Implicit none

ç тотальный контроль за наличием описания для каждого объекта

Interface
         .. ..
 
 
end Interface

Ë- шаблоны для вызова внешних ПП , включая заголовок с параметрами и их описания, взятые прямо из текста самой ПП

Type .. .. endType

Объявления производных типов

parameter Real integer complex logical    character

Type
      dimension

Описания констант, переменных и массивов  

  • для формальных параметров  ..P
  • для глобальных объектов программы-носителя Имя

 списки ввода-вывода namelist

m format(..f)

 - формат вывода – описание, которое, в отличие от других, -
в любом месте, даже среди исполняемых операторов

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

В порядке выполнения, но можно его  изменить с помощью do if where selectCase return  stop 

Модуль – без Исполняемых операторов

CONTAINS

Отделяет носитель от вложенных ПП

  • не нужен, если вложенных ПП нет
  • далее ПП, для которых Имя - носитель данных

Subroutine ИмяS1
.. ..
end Subroutine
ИмяS1

Function ИмяF1
.. ..
end Function
ИмяF1

 

Здесь располагаются ПП

·        Внутренние, заимствующие объекты у программы-носителя

·        модульные, заимствующие объекты у модуля

END     ·        PROGRAM    Имя

·        SUBROUTINE Имя

 

·        FUNCTION    Имя

 

·        MODULE      Имя

Конец текста программы с именем - можно просто end

Конец текста внешней процедуры лучше с именем

Конец текста модульной процедуры обязательно с именем

Конец текста внешней функции лучше с именем

Конец текста модульной функции обязательно с именем

Конец текста модуля обязательно с именем

 *)  находятся внутри модуля после contains

 

 

Связь одноименных объектов программы-носителя и вложенной подпрограммы разрывается: в каждой из программ свои объекты, не смотря на одинаковые имена !

 

 
Область видимости локальных объектов и глобальных объектов для программной единицы (ПЕ), использующей модуль

 

 

На картинке показано присоединение глобальных объектов модуля в область видимости внешней ПЕ

  • оператор  use ИмяМодуля заимствует у модуля и делает видимыми глобальные объекты модуля, что показано в виде бирюзового конуса
  • толстой пунктирной синей линией показано, на какие глобальные объекты модуля непосредственно направлено действие команд внешней ПЕ
  • толстой сплошной синей линией обозначен вызов модульных подпрограмм, напрямую объекты модуля не упоминаются
  • косвенное обращение к глобальным объектам модуля со стороны внешней ПЕ показано транзитом через вызов модульных ПП (толстая сплошная синяя линия) и далее посредством команд модульной ПП (сплошная жирная желтая линия)

Программирование только с использованием глобальных объектов через посредство модульных ПП называют инкапсуляцией. Такая манера работы позволяет разделить программу и данные, что важно при длительном сопровождении программы. В этом случае изменение структуры данных внутри модуля, возможно, затронет модульные ПП, но не повлечет за собой изменение внешних программ.

Возможны различные сочетания вариантов присоединения глобальных объектов

  • сочетание обеих возможностей -  заимствование объектов и у носителя, и у модуля
  • Модуль использует другой модуль, присоединяя его объекты
  • Внутренняя подпрограмма использует объекты модуля не напрямую, а через посредство носителя
  • При использовании модуля можно заказать только (only) какие-то из его объектов, например, для устранения коллизии имен
  • При использовании модуля можно заменить при помощи составного знака => некоторые из используемых имен на свои названия, например, для устранения коллизии имен
  • По вызовам ПП зацикливание возможно (это вызов, в конечном счете, самое себя - рекурсия)
  • По использованию модулей рекурсия запрещается. Использование самое себя то есть определение само через себя абсурдно.

 

Модули 

В Ф90 появилось принципиально новое понятие Модуля. Модули предназначены для интегрирования большого количества данных, циркулирующих между многими программами солидного проекта.  Модули призваны заменить common и include, объявленные в Ф90 устаревшими.

Модуль надо лишь упомянуть, чтоб стали видимыми его объекты, а каждый common-блок надо прописывать со всеми его объектами в каждой ПП, где эти объекты упоминаются, подгоняя адреса.

Оператор include просто включает текст операторов описания в текст программы. В отличие от него использование модуля

·       только в простейшем варианте присоединяет описание объектов, тем не менее, не удлиняя текста программы

·       а также присоединяет шаблоны программ

·       дает механизм реализации принципа инкапсуляции

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

 

Заголовок

MODULE  Имя

модуль– обязательно без параметров

! комментарии

Располагаются в любом месте программы

Use ИмяМ1

Модуль может использовать другие модули

Æ видим глобальные public-объекты в модуле ИмяМ1
Æ доступны процедуры и функции из модуля ИмяМ1

+ применимы шаблоны из модуля ИмяМ1 для вызова ПП

Implicit none

ç тотальный контроль за наличием описания для каждого объекта

Interface
         .. ..
 
 
end Interface

Ë- шаблоны для вызова внешних ПП , включая заголовок с параметрами и их описания, взятые прямо из текста самой ПП

Type .. .. endType

Объявления производных типов

parameter Real integer complex logical    character

Type
      dimension

public  private

Описания констант, переменных и массивов  

  • для глобальных объектов модуля Имя
  • и public-объекты,  и private-объекты видны в модульных ПП

 

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

Модуль – без Исполняемых операторов

CONTAINS

Отделяет носитель от вложенных модульных подпрограмм

  • не нужен, если вложенных ПП нет
  • далее ПП, для которых Имя - носитель данных

Subroutine ИмяS1
.. ..
end Subroutine
ИмяS1

Function ИмяF1
.. ..
end Function
ИмяF1

 

Здесь располагаются ПП

·        Внутренние, заимствующие объекты у программы-носителя

·        модульные, заимствующие объекты у модуля

Модульные ПП можно вызывать из внешних ПЕ, использующих модуль Имя

END   MODULE  Имя

Конец текста модуля обязательно с именем

Модуль предоставляет возможность объявить данные, общедоступные для многих внешних ПЕ. В отличие от ПЕ непосредственно в модуле нет действий. Однако внутри модуля после слова CONTAINS могут содержаться Модульные  ПП. В любую из модульных подпрограмм после слова  CONTAINS можно вложить пачку внутренних ПП. Модульные  подпрограммы и их внутренние подпрограммы заимствуют объекты (и Public, и Private) у модуля. Получается, что модуль - это трехэтажная конструкция: модуль - модульные  ПП - внутренние  ПП. Важнейшее предназначение модуля состоит в том, чтобы упаковать какие-либо данные, сделав их доступными в главной программе или любой внешней ПП простым использованием имени модуля в операторе  USE  ИмяМодуля. Приветствуется, чтобы в модуле как бы в одной упаковке с данными были бы припрятаны и модульные подпрограммы для обработки этих данных. Слово “припрятаны” носит принципиальный характер: чем лучше продуман модуль - тем меньше есть причин, чтобы обращаться к данным, минуя модульные ПП. В идеале модуль достигает совершенства, когда такого доступа вообще нет.

Рассмотрим модули сначала более простые и понятные по назначению, потом посложнее

MODULE   ИмяМ1

Public - Общедоступные данные

 

End MODULE   ИмяМ1

 

ß×

Программа Имя1

Use ИмяМ1 …………

 

 

 

ß×

Программа Имя2

Use ИмяМ1 ………

 

MODULE   ИмяМ2

Interface

Шаблоны всех внешних процедур для централизованного контроля

End Interface

 End MODULE   ИмяМ2

 

ß×

Программа Имя1

Use ИмяМ2, except_this_one => Имя1

все шаблоны ПП, кроме данной Имя1

 

 

 

ß×

Программа Имя2

Use ИмяМ2, except_this_one=>Имя2

все шаблоны ПП, кроме данной Имя2

 

MODULE   ИмяMПрТип

   Определение производного типа данных

Contains

 

Все процедуры, функции доступа к данным этого типа

Например, как создать,

как выбрать, как занести,

как "обнулить"

 

 End MODULE ИмяMПрТип

 

ß×

Программа Имя1

Use ИмяMПрТип

 

 

 

ß×

Программа Имя2

Use ИмяMПрТип

………

 

Сама система программирования в Ф90 также опирается на использование модулей. Отметим самый важный модуль
 
use MSFLIB он содержит константы, объявления производных типов, интерфейсы, функции

  • для низкоуровневой графики
  • для QuickWin – быстрого безболезненного перехода от ДОС к стилю Windows

 

Общие блоки памяти

Глобальные объекты размещают в общих блоках памяти,  которые по идеологии наиболее близки к языку С. В Ф-90 это средство отнесли к устаревшим наряду с новым устаревшим оператором include также весьма характерным для С. После появления модулей эти средства кажутся действительно архаичными. В модулях не надо так скрупулезно как в общих блоках памяти подсчитывать адреса и отслеживать раскладку данных по разным блокам. Краткое описание приводится только для понимания ранее написанных программ и чтобы убедиться в том, что новые программы стоит писать только с использованием модулей.

Общие блоки памяти – это старинная альтернатива передаче данных через параметры, когда данных слишком много. Оператор Common { /ИМЯ/ ..v } размещает в общем блоке  /ИМЯ/ объекты в порядке перечисления их в  списке  ..v  , здесь ИМЯ - это глобальное имя, уникальное в рамках задачи. В одном  операторе Common можно описать несколько общих блоков памяти. В каждой ПЕ описывают те общие блоки, объекты из которых упоминаются в программе.

Если данные размещены в модуле, то достаточно упомянуть только модуль, не перечисляя его объекты.

Допускаются любое количество именованных блоков и один безымянный (у него /ИМЯ/ отсутствует). Если имена блоков являются глобальными, то имена объектов из списка  ..v  локализованы в ПЕ. Сопоставление данных в разных ПЕ выполняется только по адресам от начала блока, что в “C” рассматривается как поля внутри записи. Как это делается поясняется на примере:

 

Subroutine S1     ! процедура 1

real a,r,X

common /Block/ a,r, X(10)

Subroutine S2    ! процедура 2

real F,G

common /Block/ f(2), G(20)

адрес в /Block/

 1

 5

 9 

11

 ..

 

/Block/ в S1

 a        4 байта

 r         4 байта

 X1        4 байта

 X2        4 байта

..

 X10         4 байта

всего 48 байтов

/Block/ в S2

   f1        4 байта

   f2     4 байта

   G1      4 байта

   G2      4 байта

..

   G20     4 байта

всего 88 байтов

 Длину блока в разных ПП можно варьировать: компоновщик отведет память по максимуму.

Оператору Common /ИМЯ/ ..v из Фортрана в языке "С" соответствует

                 external struct { ..v } ИМЯ ;  причем ИМЯ должно состоять только из прописных букв.

 

Примеры  функций, подпрограмм и программ

 

Примеры 1.1-1.3 иллюстрируют решение одной и той же задачи ”найти максимальный элемент массива” несколькими способами

Пример 1.1. Встроенная функция max и процедура maximum.

 Program  maximum     !  программа  maximum    

  real X(12) , Xm 

    read (*,*) X ;     write (*,*) '  массив X='  , X 

    call maximum (Xm,X )

    write (*,*) ' Xmax='  , Xm 

end Program  maximum

     

SUBROUTINE maximum (Rmax,R )

  real R(12) , Rmax 

    Rmax = R(1)

      do k=2,12

        Rmax  = max ( R(k), Rmax  )     !    Встроенная функция max (a,b)

       end do  !  k=2,12

end SUBROUTINE maximum 

 

Пример 1.2. Встроенная функция max и функция maxima.

Program  maxima     !  программа  maxima    

  real R(12) , Rmax 

    read (*,*) R ;     write (*,*) '  массив R='  , R 

    write (*,*) ' Rmax='  , Rmax(R)

end Program  maxima

 

real FUNCTION Rmax  (R )

  real R(12)

    Rmax = R(1)

      do k=2,12

        Rmax  = max ( R(k), Rmax  )     !    Встроенная функция max (a,b)

      end do  !  k=2,12

end FUNCTION Rmax 

 

Пример 1.3. Встроенная функция maxVal - найти максимальный элемент массива.

Program  maxima     !  программа  maxima    

  real R(12) , Rmax 

    read (*,*) R ;     write (*,*) '  массив R='  , R 

    write (*,*) ' Rmax='  , maxVal(R)

end Program  maxima

 

 

Пример 2. Создание альтернативного интерфейса для работы с целыми и вещественными массивами

 

INTERFACE maxi  ! generic name of maxi  - родовое имя maxi  для работы с целыми и вещественными массивами

 

    real FUNCTION rmaxi  (R )

      real,intent(IN), dimension (1:12)::  R

    end FUNCTION rmaxi 

 

    integer FUNCTION imaxi  (R )

      integer,intent(IN) ::  R(12)

    end FUNCTION imaxi 

 

END   INTERFACE  maxi 

Надо написать две ПП – одну rmaxi  для поиска максимума в вещественном массиве, другую  imaxi  для поиска максимума в целом массиве. Тогда показанный интерфейс позволит использовать родовое имя maxi одинаково успешно и для целого и для вещественного массива. Иначе говоря, функция будет перенимать тип у аргумента, используя так называемый механизм перегрузки.

 

Пример 3. Операторная функция. 

Формулу

    можно упро­стить до t = ( s(a,2.5) - s(b,1) )  /  s(a,b)   , введя обозначение s(x,y) = .

Program operFun  ! То же самое напишем в программе:

   real x,ya,b, s, T

     s(x,y) = sqrt(x*x - y*y )    ! определение операторной функции

 read (*,*) x,y  ;      write(*,*) ' x=' , x,    '   y=' , y

 T = (   s(a,2.5) - s(b,1.0)   )  /  s(a,b)   ! многократный вызов операторной функции

 write(*,*)   ' T = ',   T

end Program operFun 

 

Пример 4. Иллюстрируется реализации одной и той же задачи вычисления факториала, как программ разного вида.

Вычислить факториал  n! = 1*2*3*.. *n . Из математики известен особый случай: 0!=1

 

 Пример 4.1. Повторяет подпрограмму-функцию Factorial  из учебного проекта.

Function Factorial ( n )  ! заголовок  подпрограммы-функции

   real*8 Factorial   ! тип результата     

     integer,intent(in) :: n  ! единственный входной параметр

        integer k ! при умножении автоматически переводится а двойную точность

   Factorial = 1

   if ( n = = 0  ) return     !  из математики известен особый случай: 0!=1

    do k=1,n

      Factorial = Factorial *k

    enddo

end Function Factorial

 

Пример 4.2. Функцию Factorial  из учебного проекта, можно определить по-другому, используя стандартную векторную функцию product

Function Factorial ( n )  ! заголовок  подпрограммы-функции

   Integer k  

     real*8 Factorial    ! тип результата

 if ( n > 0  ) then

      Factorial =product(  (/dble(k), k=1,n)  /)  )

                                            ! dble(k) преобразует тип аргумента в вещественный двойной точности

                                        ! ( dble(k), k=1,n )  - неявный цикл

                                     ! (/ (  dble(k), k=1,n)  /)  - конструктор массива

                  !  product(  (/ (  dble(k), k=1,n)  /)  )  - векторная функция, вычисляющая произведение

 Else

      Factorial = 1

 Endif

End Function Factorial

 

Пример 4.3. Функцию Factorial  из учебного проекта можно оформить не только как самостоятельную ПЕ, но и как операторную функцию, объявленную в составе ПП Loto. Изменилось определение функции  Factorial , но не изменился вызов функции Factorial.

Subroutine Loto ( m,n, S,P )  ! заголовок подпрограммы  Loto

   Integer,intent(in) :: m, n   !  (in) - входные параметры

     real,intent(out) ::  S,P    !  (out) - выходные параметры

        Integer k   !   это описание используется в  определении операторной функции Factorial

           real*8 Factorial    !   тип (dble(k)) => тип(product) => тип(Factorial)

              операторная функция в составе ПП Loto

                 Factorial(n) = product( (/ ( dble(k), k=1,max(1,n) ) /) )

                     !      при n=0 получим max(1,0)=1,
                     ! но при
n=1 и при n>1 получим max(1,n)=n

    S = Factorial(n) / ( Factorial(m)* Factorial(n-m) ) ! вызов функции не меняется

    P = 1 / S

 End Subroutine Loto

 

  Пример 4.4. Реализует  вычисление факториала  из учебного проекта вообще не в виде функции, а в виде процедуры

  • не изменился способ вычисления факториала и имя входного параметра n
  • изменился вид ПП с function на Subroutine и ее имя с Factorial на proFact, изменился интерфейс
  • подпрограмму  вида Subroutine по имени proFact только вызывают, но с ее именем не связывают результатов
  • тот же результат Factorial стал выходным параметром вместо имени функции
  • в соответствии с интерфейсом изменится вызов подпрограммы

interface

   SUBROUTINE proFact ( n, Factorial)  ! заголовок  процедуры

      integer,intent(in) :: n                !   как и был, единственный входной параметр

      real*8 ,intent(out) :: Factorial   !   добавился выходной параметр вместо имени ПП-функции

   end SUBROUTINE proFact

end interface

 

Оболочка, показанная крупным жирным шрифтом, у ПП сменилась, а начинка – нет.

SUBROUTINE proFact ( n, Factorial)  ! заголовок  процедуры

     integer,intent(in) :: n  ! единственный входной параметр

     real*8 ,intent(out) :: Factorial   ! тип результата     

                    integer k

                    Factorial = 1

                    if ( n = = 0  ) return    

                   do k=1,n

                       Factorial = Factorial *k

                   enddo

end SUBROUTINE proFact

 

В соответствии с интерфейсом изменится вызов подпрограммы из ПП Loto  -  добавятся новые промежуточные переменные factorN,   factorN,   factorNM

integer n,m;  real*8 factorN,   factorN,   factorNM,  S     

 Call proFact(n,factorN)

    Call proFact(m,factorM)

      Call proFact(n-m,factorNM)

          S = factorN  /  ( factorM)*factorNM )

Оценивая 4 варианта реализации вычисления факториала, можно отметить следующее

  • вычисление факториала предпочтительнее оформить не в виде процедуры, см. 4.4, а в виде функции, которую легче вызывать
  • это можно сделать, потому что результат – одно число
  • вызов функции не меняется, если ее по-разному определять, см. 4.1, 4.2, 4.3
  • самое краткое определение – у операторной функции, см. 4.3, видимо, из-за использования стандартных функций product, dble,max

 

 Пример 5. Иллюстрация к использованию оператора external для передачи имени программы

  • пусть подпрограмма koren умеет численно решать уравнение f(x)=0, находя один корень xkor
    с заданной степенью точности 
    eps  для любой функции f(x) в заданном интервале [a,b]
  • требуется решить два уравнения  
    x3+x2-3x+4=0     (F1)  
    x3-x2-3x + 4=0    (F2) 
  • чтоб сделать подпрограмму koren действительно универсальной
    надо передавать в нее имя подпрограммы-функции f(x), реализующей левую часть уравнения
    f(x)=0 
  • объявим как External F1,F2 - внешние имена функций для левых частей двух уравнений F1(x)=0  и  F2(x)=0
  • имена ПП-функций F1 и  F2, соответственно, передадим в качестве фактических параметров в двух вызовах ПП  koren
  • сами по себе подпрограммы F1 и  F2 крайне простые, но, чтобы воспользоваться универсальной ПП  koren, без них не обойтись
  • на рисунке показан график F2(x)=0 , ищется корень  x2~ =1.5 справа от оси OY в интервале [0,2]
  • для понимания примера приводится лишь интерфейс ПП koren

program External_for_koren

real :: F1,F2,    eps=0.0001 

real ::    a1 = -4,  b1= -2,    x1       !  корень  x1 для F1(x)=0    в [-4,-2]

real ::    a2=0,      b2=2,      x2       !  корень  x2 для F2(x)=0    в [0,2]

External F1,F2   ! имена внешних ПП-функций, вычисляющих левые части двух уравнений f(x)=0 

 interface  

   subroutine koren (xkor,a,b, eps,   f )   ! решает любое уравнение f(x)=0 

     real, intent(in) :: a,b       !  интервал [a,b] с одним корнем

     real, intent(in) :: f          !   левая часть уравнения f(x)=0 

     real, intent(in) :: eps      !   точность для искомого корня

     real, intent(out) :: xkor  ! это ответ - найденный корень

   end subroutine koren

end interface  

 

Call koren (x1,a1,b1, eps,    F1)  ! для уравнения F1(x)=0     !   x1 ~ = -3    находится в [-4,-2]

Call koren (x2,a2,b2, eps,    F2) ! для уравнения F2(x)=0      !   x2~ =1.5    находится в [0,2]

 

end program External_for_koren

 

real  function F1(x)

  real  x

    F1=x**3+x**2-3*x+4

End function F1

 

real  function F2(x)

  real  x

    F2=x**3-x**2-3**x+4

End function F2

 

Hosted by uCoz
.

 

 Web-design Звягин В.Ф. со товарищи: Аминев Р.Ш..
197101, Россия, Санкт-Петербург, ул.Саблинская, 14
ИТМО
Hosted by uCoz