Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Аверянов Введение в оператсионные системы и основы программирования 2015

.pdf
Скачиваний:
4
Добавлен:
12.11.2022
Размер:
4.77 Mб
Скачать

Бинарная операция, примененная к двум массивам, имеет такой же результат, как если бы эта операция была попарно применена к элементам первого и второго массива с одинаковыми номерами (индексами). Это легко можно увидеть на примере арифметических операций (см. табл. 3.3) между одномерными (пример 3.61) и двумерными (пример 3.62) массивами вещественных чисел, т.е. операции с массивами не имеют ничего общего с операциями над матрицами или векторами.

Допускаются бинарные операции между массивами и скалярами. Действие бинарной операции между массивом и скаляром равноценно совокупности операций между скаляром и всеми элементами массива, например операция умножения суммарного массива A+B (см. пример 3.62) на скалярную переменную X = 2 равноценна удвоению каждого элемента этого массива. Действие унарных операций (например, унарный минус) имеет аналогичный характер.

Пример 3.62. Объявление и инициализация массива констант с указанием верхней границы (вариант 2)

program OPERARR2

integer, parameter, dimension(2, 2):: A = RESHAPE ((/ 0, 1, 2, 3 /), (/2, 2/) ) integer, parameter, dimension(2, 2):: B = RESHAPE ((/ 4, 5, 6, 7 /), (/2, 2/) ) integer, dimension(2, 2):: C; integer :: X = 2

C = X*(A+B)

I=1; print*, (A(I, J), J = 1, 2); I=2; print*, (A(I, J), J = 1, 2) I=1; print*, (B(I, J), J = 1, 2); I=2; print*, (B(I, J), J = 1, 2) I=1; print*, (C(I, J), J = 1, 2); I=2; print*, (C(I, J), J = 1, 2) end

Для пояснения текста программы (см. пример 3.62) полезно напомнить, что для инициализации массивов A и B используется функция RESHAPE, позволяющая переформатировать одномерные массивы к требуемой форме. В данном случае эта функция содержит два аргумента (в круглых скобках, через запятую): первым аргументом является конструктор одномерного массива констант, а вторым аргументом − константа, определяющая форму конечного массива (см. п. 3.3.6).

171

3.5.УПРАВЛЯЮЩИЕ ОПЕРАТОРЫ

3.5.1.Условный оператор и конструкция IF

Условный оператор IF проверяет значение скалярного логического выражения. Если его значение истинно, т.е. имеет значение «.TRUE.» (см. п. 3.3.3), то выполняется действие в виде одиночного оператора (например, вывод на печать, присваивание и т. д.). Обрамляющие круглые скобки для условия обязательны:

IF (условие) одиночный оператор

Оператору IF не могут в качестве действия указываться другие условные операторы и конструкции, а также циклы. Условием может быть логическая константа, переменная или выражение – чаще всего это логические отношения, связанные логическими операто-

рами (см. п. 3.4.3).

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

Пример 3.63. Пример использования логического оператора IF program SIGNDETECT

integer NUMBER read*, NUMBER

if(NUMBER > 0) print*, “Положительное” if(NUMBER < 0) print*, “Отрицательное” if(NUMBER == 0) print*, “Нуль”

end

Оператор IF позволяет выполнить одиночный оператор (или исключить его выполнение при невыполнении условия) – это в ряде случаев позволяет обеспечить компактность программы, но явно недостаточно, если в качестве альтернатив используются последовательности более чем из одного оператора. В этом случае целесообразно использовать конструкцию IF.

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

172

ет проверяемое условие (логическая величина) и ключевое слово THEN. После THEN в первой строке конструкции IF не может быть ничего, кроме комментария. Если строка – длинная, она может быть продолжена в соответствии с правилами продолжения строк свободного или фиксированного формата. После первой строки конструкции IF следует последовательность операторов, выполняемых при истинности проверяемого условия:

IF (условие) THEN

блок операторов

ELSE IF (альтернативное условие 1) THEN альтернативный блок операторов 1 ELSE IF (альтернативное условие 2) THEN альтернативный блок операторов 2

ELSE IF (альтернативное условие N) THEN альтернативный блок операторов N

ELSE

пост-альтернативный блок

END IF

Далее в конструкции IF могут присутствовать число альтернативных блоков ELSE IF со своими условиями – правила их записи точно такие же, как для первого IF-блока. Количество блоков ELSE IF не ограничено – их может быть и десять и сто, а может не быть ни одного.

Затем после блоков ELSE IF может следовать (или отсутствовать) блок ELSE, содержащий программный код, выполняемый в отсутствие истинности всех условий IF и ELSE IF. После чего для завершения конструкции IF используется оператор END IF.

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

IF (условие) THEN

блок операторов

END IF

173

В качестве примера c одним альтернативным блоком в конструкции IF рассмотрим определение четности целого числа, введенного с клавиатуры.

Для определения четности числа используется правило целочисленной арифметики, при делении целых чисел дробная часть отбрасывается. Если четное целое число сначала разделить на два, а затем результат деления опять умножить на два, получится то же самое четное число, что и до деления. Если ту же операцию проделать с нечетным числом, то при делении на два дробная часть будет отброшена и при умножении результата деления на два исходное нечетное число не восстановится (пример 3.64).

Пример 3.64. Пример логической конструкции IF с альтернативой program EVENDETECT

integer NUMBER logical EVEN read*, NUMBER

EVEN = NUMBER / 2 * 2 == NUMBER if(EVEN) then

print*, “Четное”

else

print*, “Нечетное” end if

end

Развернутую конструкцию IF можно показать на примере, где одновременно определяется знак и четность целого числа, введенного с клавиатуры (пример 3.65).

Пример 3.65. Пример логической конструкции IF с множеством альтернатив

program EVENSIGN integer NUMBER logical EVEN read*, NUMBER

EVEN = NUMBER / 2 * 2 == NUMBER if(EVEN .and. NUMBER > 0) then

print*, “Четное положительное” else if(EVEN .and. NUMBER < 0) then print*, “Четное отрицательное”

else if((.not. EVEN) .and. NUMBER > 0) then print*, “Нечетное положительное”

else if((.not. EVEN) .and. NUMBER < 0) then

174

print*, “Нечетное отрицательное”

else

print*, “Нуль” end if

end

Для конструкций IF допускается произвольная вложенность при условии, что вложенные элементы не пересекаются.

3.5.2. Оператор варианта – конструкция CASE

Подобно конструкции IF конструкция CASE позволяет выполнять тот или иной блок операторов, в зависимости от определенного условия. Условие выбора задается значением скалярного выражения целого, логического или текстового типа. Выражение, определяющее условие выбора, должно быть записано в круглых скобках в операторе SELECT CASE:

SELECT CASE (выражение) CASE селектор 1

блок операторов 1 CASE селектор 1

блок операторов 1

CASE селектор N

блок операторов N

CASE DEFAULT

блок операторов

END SELECT

Для выбора блока операторов необходимо, чтобы селектор оператора CASE этого блока содержал элемент, совпадающий по значению с выражением в SELECT CASE. Общая форма селектора – заключенный в скобки список неперекрывающихся значений и интервалов того же типа, что и выражение, определяющее условие выбора блока исполняемых операторов.

175

В качестве примера (пример 3.66) можно запрограммировать алгоритм определения четности целых чисел (тот же алгоритм, что и в примере 3.64).

Селекторы могут задаваться списком, диапазоном или комбинировано (диапазон, как элемент списка). При этом диапазоны значений селекторов не должны пересекаться в пределах одной конст-

рукции SELECT CASE (пример 3.67).

Пример 3.66. Пример логической конструкции IF с альтернативой program EVENCASE

integer NUMBER logical EVEN read*, NUMBER

EVEN = NUMBER / 2 * 2 == NUMBER select case (EVEN)

case (.TRUE.) print*, “Четное”

case (.FALSE.)

print*, “Нечетное” end select

end

Пример 3.67. Задание селекторов в виде списка и закрытого диапазона program DETECTSYM

character SYMBOL read*, SYMBOL select case (SYMBOL)

case(“–” , “+”, “/”, “*”) ! Селектор в виде списка print*,'Арифметический оператор'

case(“0”: “9”) ! Селектор в виде закрытого диапазона значений print*,'Цифра'

case default print*,'Неизвестный символ'

end select end

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

Закрытый диапазон значений задается своей левой и правой границами, разделенными двоеточием. Соответственно, в диапазоне, открытом слева, отсутствует левая граница, а в диапазоне, открытом справа, – правая граница. По своему смыслу открытые

176

диапазоны аналогичны логическим отношениям «меньше либо равно» и «больше либо равно».

Конструкция CASE может содержать не обязательный блок, начинающийся строкой CASE DEFAULT. В этот блок входят операторы, выполняемые, если все прочие CASE-блоки не сработали. Такой блок не обязательно должен быть последним.

Пример 3.68. Задание селекторов в виде закрытого и открытого диапазона program SUBSTEMP

!Состояние субстанции, как функция температуры. integer TEMPERATURE, ABSNUL, FLAME parameter(ABSNUL = –273, ICE = 0, FLAME = 1000000) read*, TEMPERATURE

select case (TEMPERATURE) case(:–273)

print*, “Давно замерзло все, что можно” case(ABSNUL:ICE)

print*, “Лед” case(FLAME:)

print*, “Пламень” case default

print*, “Туман и сырость” end select

end

3.5.3. Циклы – разновидности конструкции DO

При решении математических задач, связанных с вычислением последовательностей, полиномов и рядов, возникает необходимость вычисления одинаковых по структуре выражений, зависящих от номера элемента, а также суммирования этих выражений, вычисления произведений и т.д. Для программной реализации таких алгоритмов практически во всех императивных языках программирования предусмотрены циклические конструкции. В Фортране 90/95 для этих целей используется конструкция DO.

Наиболее часто используются циклы в виде конструкции DO с фиксированным числом повторений, имеющие общий вид:

DO переменная цикла = нач_знач, кон_знач, шаг_изм блок операторов

END DO

177

В операторе DO указывается переменная цикла, которой при-

сваивается начальное значение и через запятую конечное значение и шаг изменения переменной цикла. В строках, следующих за оператором DO, записываются операторы, выполняемые в цикле. Завершается конструкция цикла оператором END DO.

Переменная цикла – скалярная целая переменная, а ее начальное, конечное значения и шаг изменения должны быть скалярными целыми выражениями. Если шаг изменения переменной цикла равен единице, то его можно не записывать, т.е. первая строка конструкции DO будет выглядеть как:

DO переменная цикла = нач_знач, кон_знач

Число итераций цикла может быть вычислено по формуле:

(кон_знач – нач_знач + шаг_изм)/ шаг_изм)

Если результат меньше нуля, цикл игнорируется. На практике, чтобы цикл был рабочим (не вырожденным) необходимо чтобы при положительном шаге конечное значение переменной было больше начального, а при отрицательном шаге – наоборот: начальное больше конечного.

Следует особо отметить, что в первой строке цикла оператор DO должен быть единственным оператором.

В качестве простейшего примера использования конструкции DO можно рассмотреть вычисление суммы целых чисел от единицы до N (пример 3.69). Здесь переменная цикла I изменяется от единицы до N (введенного с клавиатуры) с шагом «единица» (можно не писать). На каждой из N итераций цикла к изначально нулевой сумме (переменная SUM) прибавляется очередное число.

Пример 3.69. Вычисление суммы целых чисел от единицы до N program SUMN1

integer :: SUM = 0 !Инициализация суммы read*, N

do I = 1, N

SUM = SUM + I end do

print *, “SUM=”, SUM end

178

Этот пример можно модифицировать несколькими способами. 1. Просуммировать числа от N до единицы, заменив

«DO I = 1, N» на «DO I = N, 1, –1».

2.Просуммировать только нечетные числа от единицы до N,

заменив «DO I = 1, N» на «DO I = 1, N, 2».

3.Просуммировать только четные числа от единицы до N, за-

менив «DO I = 1, N» на «DO I = 2, N, 2».

4.Вычислить произведение чисел от единицы до N (факториал числа N, обозначаемый N!), инициализировав переменную SUM не нулем «SUM = 0», а единицей «SUM = 1» и заменив накопление суммы чисел «SUM = SUM + I» накоплением произведения «SUM = SUM * I», можно поменять и имя переменной в соответствии со смыслом новой задачи.

В нотации Фортран 77 (поддерживаемой Фортраном 90/95) цикл начинается оператором DO, в котором после ключевого слова DO сначала указывается метка (например, «100») последнего оператора тела цикла, а затем, как и в конструкции DO, переменная цикла, диапазон ее изменения и шаг. Далее следует тело цикла, завершающееся оператором, помеченным меткой, указанной в операторе DO. Как правило, меткой помечается «пустой» (не вызывающий какого-либо действия) оператор CONTINUE (пример 3.70). Отличительной особенностью цикла DO в Фортране 77 является то, что переменная цикла, ее границы и шаг могут быть не только целыми, но и вещественными, однако от такой экзотической особенности в последующих стандартах было решено отказаться.

Пример 3.70. Вычисление суммы целых чиселв Фортран 77 program SUMN2

integer :: SUM = 0 !Инициализация суммы read*, N

do 100 I = 1, N SUM = SUM + I

100 continue

print *, “SUM=”, SUM end

В стандарты Фортран 90/95 была внесена и тут же отнесена к избыточным и не рекомендованным свойствам языка циклическая конструкция c предусловием DO WHILE, имеющая общий вид:

179

DO WHILE (лог_выр)

блок операторов

END DO

Если при входе в цикл логическое выражение в условии DO WHILE имеет значение ИСТИНА (.TRUE.), то выполняется первая итерация цикла. Проверка осуществляется перед каждой следующей итерацией, и как только выражение будет иметь значение ЛОЖЬ (FALSE), итерации прекращаются. В качестве иллюстрации с помощью конструкции DO WHILE проведено вычисление суммы чисел (пример 3.71), аналогичное примерам 3.69 и 3.70.

Пример 3.71. Вычисление суммы целых чисел с помощью DO WHILE program SUMN3

integer :: SUM = 0, I=0 !Инициализация суммы и переменной цикла read*, N

do while(I < N) I=I+1

SUM = SUM + I end do

print *, “SUM=”, SUM end

Причина отказа от конструкции DO WHILE связана с возможными проигрышами в оптимизации программного кода, проблема подробно описана в гл. 10 работы: Optimizing Supercompilers for Supercomputers, M. Wolfe (Pitman, 1989).

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

DO

блок операторов

END DO

с включением в тело цикла операторов IF – для контроля условий, а также операторов EXIT – для выхода из текущего цикла и операторов CYCLE – передающих управление на END DO текущего цикла и, таким образом, инициирующих начало следующей итерации цикла. Операторы EXIT и CYCLE, как правило, используются в составе условного оператора IF.

180