современный фортран , Бортеньев. О. В. Бартеньев Современный Фортран
Скачать 2.24 Mb.
|
29 О. В. Бартеньев. Современный ФОРТРАН • ветвления; • цикла. 2.2.1. Блок операторов и конструкций Блок операторов и конструкций (БОК) - это выполнение одного или нескольких простых или сложных действий. БОК может содержать и ветвления и циклы, которые являются примерами сложных действий. Простым действием является, например, выполнение присваивания, В/В данных, вызов процедуры. Конструкции состоят из нескольких операторов и используются для выполнения управляющих действий, например циклов. Так, конструкция DO ... END DO состоит из двух операторов: DO и END DO. 2.2.2. Ветвление Ветвление- выбор одного из возможных направлений выполнения алгоритма в зависимости от значения некоторых условий. Различают ветвления четырех видов: • если - то; • если - то - иначе; • если - то - иначе - если; • выбор по ключу. Здесь мы рассмотрим только два первых ветвления. В ветвлениях "если - то" и "если - то - иначе" для записи условий используется логическое выражение (ЛВ), результатом которого может быть истина (И) или ложь (Л). Ветвления можно проиллюстрировать графически (рис. 2.1). И Л И Л БОК 3 БОК 2 БОК 1 ЛВ ЛВ БОК 1 БОК 2 а б Рис. 2.1. Ветвления: а - ветвление "если - то"; б - ветвление "если - то - иначе" Ветвление "если - то" работает так: • вычисляется значение ЛВ; • если оно истинно, то выполняется БОК 1 ; • если оно ложно, то управление передается БОК 2 30 2. Элементы программирования Запись ветвления "если - то" в линейной схеме алгоритма: Х°. Если истинно ЛВ, то [выполнить:] БОК1 конец если [Х°]. или, если в БОК 1 входит один оператор: Х°. Если истинно ЛВ, то [выполнить:] оператор На Фортране такое ветвление можно записать так: IF(ЛВ) THEN БОК1 END IF или так: IF(ЛВ) оператор Замечание. Оператор END IF можно записать и без пробела: ENDIF. Ветвление "если - то - иначе" работает так: • вычисляется значение ЛВ; • если оно истинно, то выполняется БОК 1 ; • если оно ложно, то выполняется БОК 2 ; • далее управление передается БОК 3 Запись ветвления "если - то - иначе" в линейной схеме алгоритма: Х°. Если истинно ЛВ, то [выполнить:] БОК1 иначе [выполнить:] БОК2 конец если [Х°]. Запись ветвления "если - то - иначе" на Фортране: IF(ЛВ) THEN БОК1 ELSE БОК2 END IF Для записи ЛВ используются логические операции и операции отношения. Также в ЛВ могут присутствовать арифметические и символьные операции. Приведем в табл. 2.1 некоторые логические операции и операции отношения в порядке убывания их приоритета. Обратите внимание, что операции отношения могут быть записаны в двух формах. В табл. 2.1 эти формы указаны одна под другой. Следует также подчеркнуть, что операция логического равенства записывается, если вы не используете форму .EQ., двумя знаками равенства (==). Пробелы в записи логических операций и операций отношения не допускаются, так, в случае операции "больше или равно" ошибочны записи .GE . и > =. 31 О. В. Бартеньев. Современный ФОРТРАН Таблица 2.1. Некоторые логические операции и операции отношения Операции Запись на Фортране Типы операций =, ≠, >, <, ≥, ≤ .EQ., ==, .NE., /=, .GT., >, .LT., <, .GE., >=, .LE. <= Отношения НЕ (отрицание) .NOT. Логическая И .AND. " ИЛИ .OR. " Пример ветвления "если - то". Определить, какое из трех заданных чисел ma, mb и mc является наименьшим. Алгоритм: 1°. Начало. 2°. Найти наименьшее из трех чисел и присвоить результат переменной m3. 3°. Если ma равно m3, то вывести сообщение "Число ma". 4°. Если mb равно m3, то вывести сообщение "Число mb". 5°. Если mc равно m3, то вывести сообщение "Число mc". 6°. Конец. Данный алгоритм позволяет найти и вывести все числа, значения которых равны минимальному. program fimin real :: ma = 5.3, mb = 7.6, mc = 5.3, m3 m3 = min(ma, mb, mc) ! Вычисление минимума if(ma == m3) write(*, *) 'Число ma' if(mb == m3) write(*, *) 'Число mb' if(ma == m3) write(*, *) 'Число mc' write(*, *) 'Минимум равен ', m3 end program fimin Результат: Число ma Число mc Минимум равен 5.300000 2.2.3. Цикл Цикл - повторное выполнение БОК, завершаемое при выполнении некоторых условий. Однократное выполнение БОК цикла называется итерацией. Операторы и конструкции БОК цикла также называются телом цикла. Различают 3 вида циклов: • цикл "спараметром"; • цикл "пока"; • цикл "до". 32 2. Элементы программирования 2.2.3.1. Цикл "с параметром" В цикле "с параметром р" задаются начальное значение параметра p s , конечное значение параметра p e и шаг s - отличная от нуля величина, на которую изменяется значение параметра р после выполнения очередной итерации. Параметр р также называют переменной цикла, которая имеет целый тип. Параметры p s , p e и шаг s являются выражениями целого типа. Графически цикл "с параметром" иллюстрирует рис. 2.2. Повтор Выход p = p s , p e , s БОК Рис. 2.2. Цикл с параметром Цикл "с параметром" работает так (случай s > 0): 1°. Присвоить: p = p s 2°. Если p ≤ p e , то перейти к п. 3°, иначе завершить цикл. 3°. Выполнить БОК. 4°. Присвоить: p = p + s и перейти к п. 2° (повтор). Когда s < 0, п. 2° выглядит так: 2°. Если p ≥ p e , то переход к п. 3°, иначе завершить цикл. Замечания: 1. В цикле "с параметром" приведенные в пп. 1° и 4° операторы в тексте программы не присутствуют, но будут автоматически встроены компилятором в объектный код при компиляции программы. 2. В цикле "с параметром" запрещается в теле цикла менять значения переменной цикла p. Изменение параметров p s , p e и шага s в теле цикла не отразится на выполнении цикла: цикл будет выполняться с теми значениями параметров, какие они имели до начала первой итерации цикла. Запись цикла "с параметром" в линейной схеме алгоритма: Х°. С параметром p = p s , p e , s [выполнить:] БОК конец цикла [с параметром p] | [Х°]. Наиболее часто цикл "с параметром" записывается так: DO p = p s , p e [, s] БОК END DO 33 О. В. Бартеньев. Современный ФОРТРАН При отсутствии шага s его значение устанавливается равным единице. Замечание. Оператор END DO можно записать и без пробела: ENDDO. Пример. Вычислить длину состоящей из n отрезков ломаной линии. Длины отрезков линии составляют последовательность a, 4a, ..., n 2 a. Пусть L - искомая длина ломаной линии. Очевидно, если первоначально положить L = 0, то, выполнив n раз оператор L = L + i 2 * a (i = 1, 2, ..., n), (*) где i -номер отрезка ломаной линии, мы получим искомый результат. Для n-кратного выполнения оператора (*) следует использовать цикл. Наиболее подходит для данной задачи цикл "с параметром", в котором в качестве параметра используется номер отрезка ломаной линии. Алгоритм: 1°. Начало. 2°. Ввести значения n и a. 3°. Принять L = 0.0. ! L - длина ломаной линии 4°. C параметром i = 1, n, 1 выполнить: ! i - номер отрезка L = L + i**2 * a конец цикла 4°. 5°. Вывод L. 6°. Конец. program polen ! Программная реализация алгоритма integer i, n real a, L ! L - длина ломаной линии write(*, *) 'Введите a и n:' read(*, *) a, n L = 0.0 do i = 1, n L = L + i**2 * a end do write(*, *) ' L = ', L end program polen Замечание. Скорость выполнения программы можно увеличить, если: • вынести из цикла операцию умножения на переменную a, значение которой в цикле не изменяется; • заменить операцию возведения в квадрат i**2 на более быструю операцию умножения i * i. 34 2. Элементы программирования Тогда фрагмент модифицированной программы будет таким: L = 0.0 do i = 1, n L = L + i * i end do write(*, *) ' L = ', L * a 2.2.3.2. Циклы "пока" и "до" Цикл "пока" выполняется до тех пор, пока "истинно" некоторое ЛВ. Причем проверка истинности ЛВ выполняется перед началом очередной итерации. Цикл "до" отличается от цикла "пока" тем, что проверка истинности ЛВ осуществляется после выполнения очередной итерации. В Фортране не существует цикла "до", но его можно реализовать в объявляющей бесконечный цикл конструкции DO ... END DO. Графическая интерпретация циклов "пока" и "до" приведена на рис. 2.3. И Л Л И ЛВ БОК БОК ЛВ а б Рис. 2.3. Циклы "пока" и "до": а - цикл "пока"; б - цикл "до" Замечание. При работе с циклами "пока" и "до" надо следить, чтобы ЛВ обязательно рано или поздно приняло значение ложь. Иначе произойдет зацикливание - "бесконечное" выполнение операторов цикла. Запись циклов "пока" и "до" в линейной схеме алгоритма и на Фортране: Цикл "пока": Х°. Пока истинно ЛВ [, выполнять:] БОК конец цикла Х°. Цикл "до": Х°. Выполнять: БОК если ложно ЛВ, то выход из цикла конец цикла Х°. DO WHILE(ЛВ) БОК END DO DO БОК IF(.NOT. ЛВ) EXIT END DO 35 О. В. Бартеньев. Современный ФОРТРАН 2.2.4. Прерывание цикла. Объединение условий Выйти из цикла и передать управление на первый следующий за циклом выполняемый оператор можно, применив оператор EXIT. Если нужно пропустить часть операторов цикла и перейти к следующей итерации, то нужно использовать оператор CYCLE. При этом управление передается операторам DO или DO WHILE. Операторы EXIT и CYCLE отдельно не применяются, а встраиваются в конструкции IF. Пример. Вычислить число положительных и отрицательных элементов одномерного массива a из n элементов, заканчивая вычисления, если число нулевых элементов массива превысит k. program pn integer, parameter :: n = 10 integer :: a(n) = (/ 1, -2, 0, 3, -4, 5, -6, 7, 0, 9 /) integer :: k = 3, pos = 0, ze = 0, i, va do i = 1, n ! i - номер элемента массива a va = a(i) if(va == 0) then ze = ze + 1 ! ze - число нулевых элементов массива if(ze > k) then exit ! Выход из цикла else cycle ! Переход на начало цикла end if end if ! pos - число положительных элементов массива if(va > 0) pos = pos + 1 end do ! Число отрицательных элементов: n - ze - pos if(ze > k) stop 'Число нулевых элементов больше нормы' write(*, *) 'pos = ', pos, ' neg = ', n - ze - pos end program pn Замечание. Использование переменной va позволяет сократить число обращений к массиву a и тем самым повысить быстродействие программы. В данной задаче для завершения цикла можно использовать широко применяемый в программировании метод объединения условий. Цикл должен продолжаться, пока истинны два условия: i ≤ n и ze ≤ k. При нарушении одного из них цикл должен быть прекращен. Используем объединение условий в цикле "пока". Алгоритм: 1°. Начало. 2°. Задать значения n, a и k. 3°. Принять: pos = 0 ! pos - число положительных элементов массива a ze = 0 ! ze - число равных нулю элементов массива a i = 1 ! i - текущий номер элемента массива a 4°. Пока i ≤ n и ze ≤ k, выполнить: 36 2. Элементы программирования va = a(i) Если va = 0, то ze = ze + 1 иначе, если va > 0, то pos = pos + 1 конец если. конец цикла 4°. 5°. neg = n - ze - pos ! neg - число отрицательных элементов массива a 6°. Вывод pos и neg. 7°. Конец. program pnw ! Программная реализация алгоритма integer, parameter :: n = 10 integer :: a(n) = (/ 1, -2, 0, 3, -4, 5, -6, 7, 0, 9 /) integer :: k = 3, pos = 0, ze = 0, i, va i = 1 ! Начинаем вычисления с первого элемента массива do while(i <= n .and. ze <= k) va = a(i) if(va == 0) then ze = ze + 1 ! ze - число равных нулю элементов массива else if(va > 0) then pos = pos + 1 ! pos - число положительных элементов массива end if i = i + 1 end do ! Число отрицательных элементов: n - ze - pos if(ze > k) stop 'Число нулевых элементов больше нормы' write(*, *) 'pos = ', pos, ' neg = ', n - ze - pos end program pnw Идея объединения условий может быть реализована при помощи флажка, например: logical fl ! Флажок - переменная логического типа i = 1 fl = i <= n .and. ze <= k ! Начальное значение флажка fl do while(fl) ! Пока значение fl есть истина, цикл выполняется i = i + 1 fl = i <= n .and. ze <= k ! Новое значение флажка end do 2.3. Программирование "сверху вниз" Разработка алгоритмов и программ осуществляется, как правило, по принципу "сверху вниз". Суть такого подхода состоит в разбиении исходной задачи на ряд более простых задач - фрагментов и последующей работе с полученными фрагментами. 37 О. В. Бартеньев. Современный ФОРТРАН При разбиении задачи на фрагменты надо придерживаться следующей схемы: 1) проанализировать задачу и выделить в ней фрагменты; 2) отобразить процесс разбиения в виде блок-схемы или линейной схемы и пронумеровать в ней фрагменты; 3) установить между выделенными фрагментами связи: для каждого фрагмента определить, какие данные он получает (входные данные) и какие данные возвращает (выходные данные). Связи между фрагментами называются интерфейсом; 4) рассмотреть далее каждый фрагмент самостоятельно; разработать для него алгоритм и записать его либо в виде линейной схемы, либо в виде блок-схемы. При необходимости подвергнуть фрагмент разбиению на более мелкие фрагменты. Такое разбиение продолжать до тех пор, пока не будут получены фрагменты, программирование которых не составляет особых затруднений; 5) оформить выделенные фрагменты в виде программных компонентов или БОК. При таком подходе программу можно рассматривать как совокупность фрагментов, которые, принимая некоторые данные, вырабатывают результат и передают его следующему фрагменту. Составляемые для фрагментов линейные схемы сопровождаются заголовком, описанием интерфейса (состава входных и выходных данных). В Фортране для реализации фрагмента можно использовать программные единицы: главную программу, модули, подпрограммы и функции. Подпрограммы и функции называются процедурами и могут быть внешними, модульными и внутренними. Модули и внешние процедуры являются самостоятельными программными единицами, доступ к которым может быть выполнен из разных программ. Подробное рассмотрение проблем разработки программных компонентов мы отложим до гл. 8. Здесь же проиллюстрируем методы программирования "сверху вниз". 2.3.1. Использование функций Фрагмент алгоритма, как правило, оформляется в виде функции, если в результате выполненных в нем вычислений возвращается единственный скаляр или массив. Пример. В каком из трех одномерных массивов a(1:10), b(1:15) и c(1:20) первый отрицательный элемент имеет наименьшее значение. Алгоритм: 38 2. Элементы программирования 1°. Ввести массивы a, b и c. 2°. Найти ma - значение первого отрицательного элемента в массиве a. 3°. Найти mb - значение первого отрицательного элемента в массиве b. 4°. Найти mc - значение первого отрицательного элемента в массиве c. ! Значения ma, mb или mc равны нулю, если в соответствующем массиве ! нет отрицательных элементов 5°. Если ma + mb + mc = 0, то Вывести сообщение: "В массивах нет отрицательных элементов" иначе Проанализировать значения ma, mb и mc и вывести имя массива, в котором первый отрицательный элемент имеет наименьшее значение. ! Алгоритм этого фрагмента приведен в разд. 2.2.2 конец если 5: 6°. Конец. Фрагменты 2°, 3° и 4° содержат одну и ту же решаемую для разных массивов задачу. В соответствии с методом программирования "сверху вниз" опишем интерфейс, т. е. входные и выходные данные фрагмента, а затем алгоритм его реализации. Интерфейс фрагмента 2° (3°, 4°): Входные данные. Одномерный массив и число его элементов. Используем внутри фрагмента для массива имя d, а для числа элементов массива - имя n. Выходные данные. Значение первого отрицательного элемента массива d или 0, если в массиве d нет отрицательных элементов. Для результата используем имя md. Алгоритм поиска первого отрицательного элемента массива: 1°. i = 1 ! i - номер элемента массива d 2°. md = d(i) ! Подготовка к циклу 3°. Пока md ≥ 0 и i < n, выполнять: i = i + 1 md = d(i) конец цикла 3°. 4°. Если md ≥ 0, то md = 0 ! Возвращаем нуль, если отрицательный 5°. Возврат. ! элемент не найден Фрагмент возвращает одно значение (md), поэтому его можно реализовать в виде функции. В Фортране переменная, в которую заносится возвращаемый функцией результат, называется результирующей и ее тип и имя (если не задано предложение RESULT) совпадают с именем и типом функции. В нашем случае функция будет иметь имя md. program nera ! Запись приведенных алгоритмов на Фортране integer, parameter :: na = 10, nb = 15, nc = 20 integer a(na), b(nb), c(nc) integer ma, mb, mc, m3 ! Поскольку функция md оформлена как |