Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
современный фортран , Бортеньев.pdf
Скачиваний:
242
Добавлен:
26.03.2015
Размер:
2.34 Mб
Скачать
! val_3 - имя конструкции

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

Следует обратить внимание на то, что вся конструкция завершается одним END IF. Ясно, что такая запись более экономна, чем запись, использующая отдельные конструкции IF THEN ELSE END IF, например:

IF(ЛВ1) THEN

IF(ЛВ1) THEN

БО1

БО1

ELSE

ELSE IF(ЛВ2) THEN

IF(ЛВ2) THEN

БО2

БО2

ELSE

ELSE

БО3

БО3

END IF

END IF

 

END IF

 

Пример. Найти число положительных, отрицательных и нулевых элементов массива.

integer :: a(100), np = 0, ne = 0, nz = 0, ca, i <Ввод массива a>

do i = 1, 100 ca = a(i)

val_3: if(ca > 0) then np = np + 1

else if(ca < 0) then ne = ne + 1

else val_3 nz = nz + 1 end if val_3 end do

...

Замечание. Подсчет искомых значений можно выполнить, применив встроенную функцию COUNT. Правда, вызвать ее придется два раза:

np = count(a > 0) ne = count(a < 0) nz = 100 - np - ne

7.3. Конструкция SELECT CASE

[имя:] SELECT CASE(тест-выражение) CASE(СП1) [имя]

[БОК1] [CASE(СП2) [имя]

[БОК2]]

...

[CASE DEFAULT [имя] [БОКn]]

END SELECT [имя]

206

7. Управляющие операторы и конструкции

Тест-выражение - целочисленное, символьное типа CHARACTER(1) или логическое скалярное выражение.

СП - список констант, тип которых должен соответствовать типу тест-

выражения.

Конструкция SELECT CASE работает так: вычисляется значение тествыражения. Если полученное значение находится в списке СП1, то выполняется БОК1; далее управление передается на следующий за END SELECT оператор. Если значение в СП1 не находится, то проверяется, есть ли оно в СП2, и т. д. Если значение тест-выражения не найдено ни в одном списке и присутствует оператор CASE DEFAULT, то выполняется БОКn, а далее выполняется расположенный за END SELECT оператор. Если же значение тест-выражения не найдено ни в одном списке и CASE DEFAULT отсутствует, то ни один из БОКi не выполняется и управление передается на следующий за END SELECT оператор.

Список констант СП может содержать одно значение, или состоять из разделенных запятыми констант, или быть задан как диапазон разделенных двоеточием значений, например 5:10 или 'I':'N'. Левая граница должна быть меньше правой. Если задается диапазон символов, то код первого символа должен быть меньше кода второго. Если опущена левая граница, например :10, то в СП содержатся все значения, меньшие или равные правой границе. И наоборот, если опущена верхняя граница, например 5:, то в СП попадают все значения, большие или равные нижней границе. СП может включать также и смесь отдельных значений и диапазонов. Разделителями между отдельными элементами СП являются запятые, например:

case(1, 5, 10:15, 33)

Нельзя задать в СП диапазон значений, когда тест-выражение имеет логический тип. Каждое значение, даже если оно задано в диапазоне значений, может появляться только в одном СП.

SELECT CASE-конструкции могут быть вложенными. При этом каждая конструкция должна завершаться собственным END SELECT.

Нельзя переходить посредством оператора GOTO или в результате альтернативного возврата из подпрограммы внутрь конструкции SELECT CASE или переходить из одной CASE секции в другую. Попытка такого перехода приведет к ошибке компиляции.

Имя конструкции, если оно задано, обязательно должны иметь операторы SELECT CASE и END SELECT.

Пример. Найти число положительных, отрицательных и нулевых элементов целочисленного массива.

integer :: a(100), np = 0, ne = 0, nz = 0, i <Ввод массива a>

do i = 1, 100

207

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

select case(a(i)) case(1:)

np = np + 1 case(:-1) ne = ne + 1

case(0) ! или: CASE DEFAULT nz = nz + 1

endselect end do

...

7.4. DO-циклы. Операторы EXIT и CYCLE

Простейшая конструкция DO

[имя:] DO

БОК

END DO [имя]

задает бесконечный цикл. Поэтому БОК должен содержать по крайней мере один оператор, например EXIT [имя], обеспечивающий выход из этого цикла. Имя конструкции, если оно присутствует, должно появляться в операторах DO и END DO.

Пример. Найти первый отрицательный элемент массива a(1:100).

i = 1

! first_n - имя конструкции DO

first_n: do

if(a(i) < 0 .or. i == 100) exit first_n i = i + 1

end do first_n

if(a(i) >= 0) stop 'В массиве нет отрицательных элементов'

print *, a(i) ! Первый отрицательный элемент массива

Рекомендуемая форма DO-цикла с параметром:

[имя:] DO dovar = start, stop [, inc]

БОК

END DO [имя]

dovar - целая, вещественная одинарной или двойной точности переменная, называемая переменной цикла или параметром цикла;

start, stop - целые, вещественные одинарной или двойной точности скалярные выражения, задающие диапазон изменения dovar ;

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

Число итераций цикла определяется по формуле ni = MAX(INT((stop - start + inc) / inc), 0),

208

7. Управляющие операторы и конструкции

где MAX - функция выбора наибольшего значения, а функция INT возвращает значение, равное целой части числа.

Если DO-цикл с параметром не содержит операторов выхода из цикла, например EXIT, то БОК выполняется ni раз.

После завершения цикла значение переменной цикла dovar равно (случай inc > 0):

dovar_ni + inc, если stop start и цикл не содержит операторов выхода из цикла, где dovar_ni - значение переменной цикла на последней итерации;

dovar_ni, если stop start и цикл досрочно прерван, например оператором EXIT или GOTO, где dovar_ni - значение переменной цикла dovar в момент прерывания цикла;

start, если stop < start.

Аналогично определяется значение dovar и для случая inc < 0. Порядок выполнения DO-цикла с параметром изложен в разд. 2.2.3.1. Нельзя изменять значение переменной цикла в теле цикла:

do k = 1, 10

k = k + 2 ! Ошибка. Попытка изменить значение переменной цикла end do

При первом выполнении оператора DO dovar = start, stop, inc вычисляются и запоминаются значения выражений start, stop и inc. Все дальнейшие итерации выполняются с этими значениями. Поэтому если stop, start или inc являются переменными и их значения изменяются в теле цикла, то на работе цикла это не отразится.

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

Рекомендуемая форма DO WHILE-цикла:

[имя:] DO WHILE(ЛВ)

БОК

END DO [имя]

Если DO WHILE-цикл не содержит операторов прерывания цикла, то БОК выполняется до тех пор, пока истинно скалярное ЛВ.

DO-цикл, DO-цикл с параметром и DO WHILE-цикл могут быть прерваны операторами GOTO, EXIT и CYCLE, а также в результате выполнения оператора RETURN, обеспечивающего возврат из процедуры.

Оператор

EXIT [имя]

передает управление из DO-конструкции на первый следующий за конструкцией выполняемый оператор. Если имя опущено, то EXIT

209

! Выход из цикла loop1
210

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

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

Оператор

CYCLE [имя]

передает управление на начало DO-конструкции. При этом операторы, расположенные между CYCLE и оператором END DO конца цикла, не выполняются. Если имя опущено, то CYCLE обеспечивает переход на начало текущего цикла, в противном случае CYCLE обеспечивает переход на начало цикла, имя которого присутствует в операторе CYCLE.

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

integer a(100), sa, c, i

<Ввод массива a>

 

sa = 0

 

do i = 1, 100

 

c = a(i)

 

if(c == 0) exit

! Досрочный выход из цикла

if(c <= 5) cycle

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

sa = sa + c

 

end do

 

print *, sa

 

Замечание. С позиций структурного программирования приведенные вычисления лучше выполнить, применив объединение условий и отказавшись от операторов EXIT и CYCLE:

sa = 0 i = 1

do while(a(i) /= 0 .and. i <= 100) if(a(i) > 5) sa = sa + a(i)

i = i + 1 end do

DO-конструкции могут быть вложенными. Степень вложения неограниченна. Вложенным DO-конструкциям следует давать имена, что повысит их наглядность и позволит в ряде случаев сократить код.

Пример. В трехмерном массиве найти первый отрицательный элемент.

integer, parameter :: L = 20, m = 10, n = 5 real, dimension(l, m, n) :: a

< ввод массива a > loop1: do i = 1, L loop2: do j = 1, m loop3: do k = 1, n

if(a(i, j, k) < 0.0) exit loop1 end do loop3

7. Управляющие операторы и конструкции

end do loop2 end do loop1

if(i > L) stop 'В массиве нет отрицательных элементов' print *, a(i, j, k)

end

При работе с DO- и DO WHILE-циклами необходимо помнить:

переменная DO-цикла с параметром dovar не может быть изменена операторами этого цикла;

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

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

если оператор IF, SELECT CASE, WHERE или FORALL появляется внутри цикла, то соответствующий ему оператор END IF, END SELECT, END WHERE или END FORALL должен быть внутри того же цикла.

Замечание. Последние три запрета легче контролировать, если соблюдать при записи программы правило рельефа (разд. 2.5).

При записи DO- и DO WHILE-циклов могут быть использованы метки. Проиллюстрируем эти формы записи на примере вычисления суммы отрицательных элементов массива a(1:100).

! Вариант 1; цикл завершается пустым оператором CONTINUE sa = 0

do 21, k = 1, 100 ! После метки можно поставить запятую if(a(k) .lt. 0) sa = sa + a(k)

21continue

!Вариант 2; вместо CONTINUE используется END DO sa = 0

do 22 k = 1, 100

if(a(k) .lt. 0) sa = sa + a(k)

22end do

!Вариант 3; цикл завершается исполняемым оператором sa = 0

do 23 k = 1, 100

23if(a(k) .lt. 0) sa = sa + a(k)

!Использующие цикл DO метка [,] WHILE варианты 4, 5 и 6 имеют те же

!различия, что и варианты 1, 2 и 3

!Вариант 4

k = 1 sa = 0

211