Главная страница
Навигация по странице:

  • 8.17. Рекурсивные процедуры

  • 8.18. Формальные процедуры

  • современный фортран , Бортеньев. О. В. Бартеньев Современный Фортран


    Скачать 2.24 Mb.
    НазваниеО. В. Бартеньев Современный Фортран
    Анкорсовременный фортран , Бортеньев.pdf
    Дата28.05.2018
    Размер2.24 Mb.
    Формат файлаpdf
    Имя файласовременный фортран , Бортеньев.pdf
    ТипДокументы
    #19729
    страница29 из 49
    1   ...   25   26   27   28   29   30   31   32   ...   49
    261

    О. В. Бартеньев. Современный ФОРТРАН
    Пример: common x, y, /com1/ a, b, // z(15) common /com1/ c(22)
    В программе будут заданы два common-блока: неименованный, в который войдут переменные x, y и массив z, и именованный - com1, содержащий переменные a, b и массив c. Конечно, для данного случая следовало бы задать common-блоки более наглядно: common x, y, z(15)
    ! Неименованный common-блок common /com1/ a, b, c(22)
    В разных программных единицах переменные одного common-блока ассоциируются с одним и тем же отрезком памяти. Порядок размещения в оперативной памяти элементов common-блока совпадает с порядком их следования в операторе COMMON.
    Длина общей области равна числу байт памяти, необходимых для размещения всех ее элементов, включая расширения за счет EQUIVA-
    LENCE-ассоциирования (прил. 2). Если несколько разных программных единиц обращаются к одному именованному common-блоку, то в каждой из них common-блок должен иметь одну и ту же длину. Неименованный com-
    mon-блок в разных программных единицах может иметь разную длину.
    Длина неименованного common-блока равна длине наибольшего существующего в программе неименованного common-блока.
    Фортран максимально уплотняет размещение переменных в памяти компьютера. При этом переменные common-блока размещаются в памяти по следующим правилам:

    переменные типа BYTE, INTEGER(1), LOGICAL(1) или CHARACTER размещаются без промежутков сразу после предшествующей переменной списка имен. То же справедливо для переменных производного типа размеров в 1 байт;

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

    символьные массивы всегда начинаются на следующем свободном байте;

    элементы любого массива следуют один за другим без промежутков;

    все common-блоки начинаются на байте, номер которого кратен четырем.
    Замечание. Программисты, использующие ассоциирование памяти, могут повысить быстродействие программ, правильно размещая переменные в common-блоке. Детально этот вопрос обсуждается в [1].
    Из-за разных принципов выравнивания символьных и несимвольных переменных в памяти ЭВМ одновременное применение символьных переменных нечетной длины и несимвольных переменных в одном common- блоке может привести к проблемам. Так, если такому смешанному common-
    262

    8. Программные единицы блоку в другой программной единице соответствует common-блок, содержащий только несимвольные переменные, то возникнут не используемые при ассоциировании байты общей области памяти. Чтобы избежать подобных явлений, не следует смешивать в одном common-блоке символьные и несимвольные данные.
    С переменными common-блока можно использовать только два атрибута: ALIAS и C. Не следует из-за приведенных проблем выравнивания использовать common-блок для доступа к структурам СИ, применяя вместо него определение типа с атрибутом EXTERN.
    Инициализация элементов именованных common-блоков выполняется в программной единице BLOCK DATA. Переменные, включенные в список
    имен common-блока, не могут быть инициализированы в операторе DATA за исключением того случая, когда оператор DATA использован в программной единице BLOCK DATA. Больше того, переменная common-
    блока не может быть инициализирована и в операторе объявления типа.
    Атрибут SAVE не может быть дан отдельной переменной common-
    блока, но может быть задан блоку целиком. Имя common-блока при этом обрамляется слешами, например: save /com1/
    ! com1 - имя common-блока
    Неименованный common-блок отличается от именованного следующими свойствами:

    после выполнения в процедуре операторов RETURN или END объекты именованного common-блока становятся неопределенными, если только
    common-блок не имеет атрибута SAVE. Объекты неименованного com-
    mon-блока всегда сохраняют свои значения после выполнения RETURN или END;

    именованный common-блок должен иметь одну и ту же длину во всех его использующих программных единицах. Длина неименованного
    common-блока может быть разной в разных программных единицах;

    объекты неименованного common-блока нельзя инициализировать в программной единице BLOCK DATA.
    Замечание. В Фортране все объекты (кроме автоматических) по умолчанию имеют атрибут SAVE. Поэтому явное задание этого атрибута именованному common-блоку полезно при создании переносимых на другие платформы программ.
    Common-блок может быть объявлен в модуле. Тогда его описание не должно появляться в использующей модуль программной единице.
    При работе с common-блоками:

    следует делать все описания данного блока одинаковыми во всех использующих его программных единицах;
    263

    О. В. Бартеньев. Современный ФОРТРАН

    следует избегать смешения в одном common-блоке разнотипных единиц памяти (из-за описанных выше проблем выравнивания). program gocom
    ! Допустимое, но нерекомендуемое различие complex (4) z
    ! описаний common-блока в разных common /vab/ z
    ! программных единицах call chaco ( ) print *, z
    ! (5.000000, -5.000000) end program gocom subroutine chaco ( ) real(4) x, y common /vab/ x, y
    ! Вещественные переменные x и y вместо x = 5.0; y = -5.0
    ! комплексной переменной z end subroutine
    Замечание. В современном Фортране common-блоки могут быть полностью заменены модулями.
    8.16.3. Программная единица BLOCK DATA
    При необходимости начальные значения элементов именованного com-
    mon-блока можно задать, используя программную единицу BLOCK DATA.
    Ее общий вид:
    BLOCK DATA [имя блока данных]
    раздел объявлений
    операторы DATA задания начальных значений элементов
    &
    общей области
    END [BLOCK DATA [имя блока данных]]
    имя блока данных является глобальным именем и не может совпадать с локальным именем переменной блока данных и с другим глобальным именем.
    Впрограммеможет быть определено несколько программных единиц
    BLOCK DATA, имеющих различные имена и выполняющих инициализацию элементов разных именованных common-блоков. Причем в программе может быть задана только одна неименованная программная единица BLOCK DATA.
    В одной программной единице BLOCK DATA может появляться несколько разных именованных common-блоков. Один и тот же common- блок не может появляться в разных программных единицах BLOCK DATA.
    Не могут быть инициализированы в BLOCK DATA объекты с атрибутом
    POINTER.
    В BLOCK DATAмогут быть использованы только следующие операторы: USE, IMPLICIT, COMMON, DATA, END, DIMENSION,
    EQUIVALENCE, POINTER, TARGET, MAP, PARAMETER, RECORD,
    264

    8. Программные единицы
    SAVE, STRUCTURE, UNION - и операторы объявления типа.
    Использование исполняемых операторов в BLOCK DATAнедопустимо.
    Присутствующие в BLOCK DATA операторы объявления типа не могут содержать атрибуты ALLOCATABLE, EXTERNAL, INTENT, OPTIONAL,
    PRIVATE и PUBLIC.
    Имя блока данных может появляться в операторе EXTERNAL. Это позволит при сборке программы загрузить из библиотеки нужный BLOCK
    DATA.
    Пример: block data bd2
    ! Этот блок может следовать сразу за complex z
    ! программой gocom предыдущего примера common /vab/ z data z /(2.0, 2.0)/
    ! Инициализация объекта common-блока end block data bd2
    8.17. Рекурсивные процедуры
    Фортран поддерживает рекурсивные вызовы внешних, модульных и внутренних процедур. Процедура называется рекурсивной, если она обращается сама к себе или вызывает другую процедуру, которая, в свою очередь, вызывает первую процедуру. В первом случае рекурсия называется
    прямой, во втором - косвенной.
    Процедура также является рекурсивной, если содержит оператор EN-
    TRY и обращается к любой задаваемой этим оператором процедуре.
    Оператор объявления рекурсивной процедуры должен предваряться префиксом RECURSIVE. Внутри рекурсивной процедуры интерфейс к этой процедуре является явным.
    Пример. Разработать подпрограмму subst, которая в данной строке заменяет все вхождения подстроки sub1 на подстроку sub2. Так, если дана строка 'abc1abc2abc3' и sub1 = 'abc', а sub2 = ' d', то результатом должна быть строка ' d1 d2 d3'. program stgo character(len = 20) :: st = 'abc1abc2abc3' call subst(st, 'abc', ' d')
    ! subst содержит прямую рекурсию write(*, *) st
    ! d1 d2 d3 end recursive subroutine subst(st, sub1, sub2) character(len = *) st, sub1, sub2 ! Длина каждой строки определяется integer ip
    ! длиной соответствующего ip = index(st, sub1)
    ! фактического параметра if(ip > 0) then st = st(:ip - 1) // sub2 // st(ip + len(sub1):) call subst(st, sub1, sub2)
    ! Рекурсивный вызов подпрограммы
    265

    О. В. Бартеньев. Современный ФОРТРАН
    end if
    ! выполняется до тех пор, пока не end ! выполнены все замены sub1 на sub2
    Если функция содержит прямую рекурсии, т. е. непосредственно вызывает сама себя, результату необходимо дать имя, отличное от имени функции. Это выполняется путем добавления в заголовок функции предложения RESULT. В случае косвенной рекурсии имя результирующей переменной и имя функции могут совпадать.
    Пример. Вычислить факториал числа n. program fact integer n /5/, ifact write(*, *) ' 5! = ', ifact(n)
    ! 5! = 120 end recursive function ifact(n) result (fav) integer fav
    ! В операторе объявления используется integer, intent(in) :: n
    ! не имя функции ifact, а имя результата fav if(n <= 1) then fav = 1 else fav = n * ifact(n - 1)
    ! Рекурсия продолжается, пока n > 1 end if end
    Тип результата рекурсивной функции можно задать и в ее заголовке, например: recursive integer function ifact(n) result (fav) или: integer recursive function ifact(n) result (fav)
    Рекурсивная процедура обязательно должна содержать проверку, ограничивающую число рекурсивных вызовов.
    8.18. Формальные процедуры
    Имя внешней, модульной процедуры и встроенной функции можно использовать в качестве фактического параметра процедуры. В этом случае соответствующий формальный параметр называется формальной процедурой.
    Формальные процедуры используются в задачах, решаемых для разных функций. Например, поиск экстремума, корня уравнения, вычисление определенного интеграла и т. д. В таких случаях создается процедура решения типовой задачи для широкого класса функций, в которую конкретная функция передается как фактический параметр.
    Имя рассматривается как имя внешней процедуры, если оно обладает атрибутом EXTERNAL. И рассматривается как имя встроенной процедуры, если имеет атрибут INTRINSIC. Если это имя используется в качестве фактического параметра процедуры, то соответствующим формальным
    266

    8. Программные единицы параметром должно быть имя формальной процедуры. Формальная процедура, если она является функцией, должна иметь тот же тип и разновидность типа, что и фактическая функция. Формальная и фактическая процедуры должны быть согласованы по числу, типу и рангу используемых в них параметров.
    Атрибуты EXTERNAL и INTRINSIC могут иметь и иное применение.
    В частности, можно описать с атрибутом INTRINSIC все используемые в блоке видимости встроенные процедуры, что сделает очевидным их применение и позволит избежать дублирования их имен локальными объектами данных.
    8.18.1. Атрибут
    EXTERNAL
    Задание атрибута EXTERNAL может быть выполнено как в отдельном операторе, так и в операторе описания типа. Последнее возможно, если мы имеем дело с процедурой-функцией.
    EXTERNAL name [, name] ...
    type-spec, EXTERNAL [, attrs] :: name [, name] ...
    type-spec - любой оператор объявления типа.
    name - имя внешней процедуры. Не может быть именем операторной функции.
    Имена внешних процедур с атрибутом EXTERNAL могут быть использованы в качестве параметров других процедур в той программной единице, в которой распространяется действие атрибута. Если у передаваемой процедуры есть родовое имя, то передаваться должно ее специфическое имя. Внутренние процедуры не допускаются в качестве параметров.
    Также атрибут EXTERNAL применяется при замене встроенной функции на пользовательскую функцию с тем же именем (разд. 8.12.2).
    Если в некоторой программной единице имя объекта имеет атрибут EX-
    TERNAL и совпадает с именем встроенной процедуры, то такая встроенная процедура в этой программной единице недоступна.
    Нельзя задать атрибут EXTERNAL функции с атрибутом TARGET.
    Процедура неявно обладает атрибутом EXTERNAL, если к ней явно задан интерфейс. При этом явное задание атрибута EXTERNAL к этой процедуре недопустимо. Следовательно, в программной единице, содержащей интерфейс к внешней процедуре, эта процедура может быть использована в качестве фактического параметра. Модульная процедура также может быть использована в качестве фактического параметра. Но так как модульные процедуры имеют явно заданный интерфейс, то их имена не должны появляться в операторе EXTERNAL.
    Пример. Написать функцию поиска корня уравнения x = f(x) с заданной точностью eps на отрезке [a, b] методом простых итераций. Начальное
    267

    О. В. Бартеньев. Современный ФОРТРАН
    приближение x0 = (a + b)/2. Используя эту функцию, найти на отрезке [0, 3] с точностью eps = 0.0001 корни уравнений
    (ответ: x = 0.5435)
    )
    1 2
    ,
    1
    /(
    1
    +
    +
    =
    x
    arctgx
    x
    и
    (ответ: x = 0.8614).
    3
    /
    )
    7
    ,
    3
    (
    +

    =

    x
    x
    e
    e
    x
    Алгоритм:
    1°. Начало.
    2°. Задать начальное приближение x0, приняв, например, x0 = (a + b)/2.
    3°. Положить x = f(x0).
    4°. Пока |x - x0| > eps, выполнить:
    x
    0 = x
    x
    = f(x0) конец цикла 4°.
    5°. Принять в качестве решения последнее значение переменной x.
    6°. Конец.
    Проиллюстрируем метод простых итераций на рис. 8.1.
    y
    y = x
    = f (x)
    y
    x
    0
    a x0 b
    Рис. 8.1. Метод простых итераций
    Условия сходимости метода простых итераций: |f
    '(x)| < 1 и f
    '(x) < 0.
    Текст программы нахождения корней заданных функций: real function fx1(x)
    ! Функции с исходными уравнениями real x fx1 = 1.0/(1.2 * atan(x) + sqrt(x + 1.0)) end function fx1 real function fx2(x) real x fx2 = (exp(-x) - sqrt(exp(x)) + 3.7) / 3.0 end function fx2
    ! Процедура поиска корня уравнения x = f(x) real function root(fx, a, b, eps) real :: fx, a, b, eps, x, x0
    ! fx - формальная процедура-функция integer :: k, itmax = 100
    ! itmax - предельно допустимое число итераций
    268

    8. Программные единицы x0 = (a + b)/2.0 x = fx(x0) k = 0 do while(abs(x - x0) .gt. eps .and. k < itmax) k = k + 1 x0 = x x = fx(x0) end do root = x end function root program firo
    ! Вариант раздела описаний с интерфейсным блоком
    ! real root
    ! interface
    ! Заданные в интерфейсном блоке
    ! real function fx1(x)
    ! процедуры обладают атрибутом
    ! real x
    ! EXTERNAL, и их можно использовать
    ! end function fx1
    ! в качестве параметров процедур
    ! real function fx2(x)
    ! real x
    ! end function fx2
    ! end interface
    ! Вариант задания атрибута EXTERNAL в операторе описания real, external :: fx1, fx2, root write(*, *) 'Корень функции fx1: ', root(fx1, 0.0, 2.0, 1.0e-4) write(*, *) 'Корень функции fx2: ', root(fx2, 0.0, 2.0, 1.0e-4) end program firo
    Замечание. Использованный критерий останова |x
    n
    - x
    n - 1
    |
    ≤ ε в общем случае ошибочен и должен быть заменен на
    ε




    q
    q
    x
    x
    n
    n
    1 1
    , где q
    ≥ |f
    '(x)|
    [7].
    8.18.2. Атрибут INTRINSIC
    Атрибут INTRINSIC означает, что обладающее им имя является родовым или специфическим именем встроенной процедуры. Родовое имя встроенной процедуры не допускается в качестве фактического параметра, а должно быть использовано ее специфическое имя. Так, недопустимо употреблять в качестве параметра родовое имя функции LOG. Вместо него, например при работе с типом REAL(4), следует описать с атрибутом IN-
    TRINSIC имя ALOG и применять затем это специфическое имя в качестве параметра процедуры.
    Задание атрибута может быть выполнено как отдельным оператором, так и в операторе описания типа.
    INTRINSIC список имен
    type-spec, INTRINSIC [, attrs] :: список имен
    269

    О. В. Бартеньев. Современный ФОРТРАН
    список имен - одно или более имен встроенных процедур (в случае нескольких имен они разделяются запятыми). Имя не может одновременно иметь атрибуты INTRINSIC и EXTERNAL. Атрибут INTRINSICне могут иметь имена определенных пользователем процедур.
    С атрибутом INTRINSIC может быть объявлена любая встроенная процедура, однако в качестве фактического параметра процедуры можно использовать только специфические имена приведенных в табл. 8.3 функций. В табл. 8.3 использованы следующие обозначения:
    Real для REAL(4) и REAL(8);
    Cmp для COMPLEX(4) и COMPLEX(8);
    Cmp(4) для COMPLEX(4);
    Cmp(8) для COMPLEX(8).
    В графе "Типы функций" указаны типы, которые функция имеет, когда она используется в качестве фактического параметра процедуры. Эта информация существенна, когда специфическое и родовое имена функции совпадают. Если родовое имя используется в выражении, то тип функции определяется типом ее параметров.
    Таблица 8.3. Специфические имена, которые допускаются в качестве
    фактических параметров
    Описание функции
    Форма вызова с
    родовым именем
    Специфи
    -
    ческие имена
    Типы
    аргументов
    Типы
    функций
    Абсолютное значение a, умноженное на знак b
    SIGN(a, b) ISIGN
    SIGN
    DSIGN
    Integer
    Real
    Real(8)
    Integer(4)
    Real(4)
    Real(8)
    MAX(x - y, 0)
    DIM(x, y) IDIM
    DIM
    DDIM
    Integer
    Real
    Real(8)
    Integer(4)
    Real(4)
    Real(8)
    x
    * y DPROD(x, y) DPROD Real Real(8)
    Усечение AINT(a) AINT
    DINT
    Real
    Real(8)
    Real(4)
    Real(8)
    Ближайшее целое ANINT(a) ANINT
    DNINT
    Real
    Real(8)
    Real(4)
    Real(8)
    Ближайшее число типа
    INTEGER
    NINT(a) NINT
    IDNINT
    Real
    Real(8)
    Integer(4)
    Integer(4)
    Абсолютная величина ABS(a) IABS
    ABS
    DABS
    CABS
    CDABS
    Integer
    Real
    Real(8)
    Cmp(4)
    Cmp(8)
    Integer(4)
    Real(4)
    Real(8)
    Real(4)
    Real(8)
    1   ...   25   26   27   28   29   30   31   32   ...   49


    написать администратору сайта