- •3.9. Ввод-вывод
- •Виды ввода-вывода данных
- •Управляемый списком ввод-вывод
- •Форматный ввод-вывод
- •3.10. Подпрограммы и функции
- •Структуры процедур
- •Вызов процедуры Вызов процедуры-подпрограммы осуществляется отдельным оператором следующего вида:
- •Упражнения
- •3.11. Массивы
- •Объявление динамических массивов
Объявление динамических массивов
Динамические массивы объявляются с атрибутом ALLOCATABLE. Каждое измерение обозначается двоеточием (:). Память под динамические массивы выделяется при выполнении программы оператором
allocate (список динамических массивов).
У каждого массива в списке должны быть указаны границы каждого измерения, значения которых предварительно могут быть вычислены или введены с клавиатуры. Для освобождения динамической памяти от размещенных в ней массивов используется оператор
deallocate (список динамических массивов)
Пример:
integer n, m
integer, allocatable :: x(:,:)
read*, n, m
allocate (x(n, m))!выделение памяти под массив x(n, m)
………..
deallocate (x) !освобождение памяти, занятой массивом
Сечение массива
Сечением массива называется некоторое подмножество его элементов. Фортран позволяет работать с сечением массива как с единым объектом данных.
Сечение массива задается с помощью индексного триплета:
[нижняя граница]:[верхняя граница]:[шаг].
Параметры триплета – целочисленные выражения. Каждый элемент триплета является необязательным.
Например, в программе описан массив:integer X(10). Возможны следующие варианты обозначения сечений этого массива:
X(:5) – первые 5 элементов массива;
X(5:) – элементы массива с 5-го по 10-й;
X(2:7) – элементы массива со 2-го по 7-й;
X(2:10:2) – все четные элементы массива;
X(::2) – все нечетные элементы массива.
Примерами сечения двумерного массива являются его строки и столбцы, например:
real p(4, 10)
p(3, :) = 0 ! 3-я строка матрицы обнуляется
p(:, 5) = 1 ! 5-й столбец матрицы заполняется единицами
Сечения массивов могут быть использованы для упрощения В/В массивов, операций со строками и столбцами (например их перестановки) и в других случаях.
Пример программы перестановки столбцов матрицы.
program Column
integer,parameter :: m=3, n=3
real, dimension(1:m,1:n) :: a
real vect(m)
real :: pr, s=0.
integer :: i, c1=1, c2=3
a(1,:)=(/1.,2.,3./) !инициализация 1-й строки с
! помощью сечения
a(2,:)=(/(i*2,i=1,3)/)!инициализация 2-й строки,
!встроенный DO-цикл
a(3,:)=(/3.,2.,1./) !инициализация 3-й строки
print *,' перестановка столбцов c1 и c2'
do i=1,n !вывод матрицы с помощью сечения
print *, a(i,:)
end do
vect = a(:,c1) !запоминание столбца c1
!сечение и vect д.б. согласованы
a(:,c1) = a(:,c2) !перестановка столбцов c1и c2
a(:,c2) = vect
print *,'Результат'
do i=1,n
print *,a(i,:)
end do
end program
Оператор WHERE
Оператор WHERE позволяет обращаться одновременно к множеству элементов массива, удовлетворяющих определенному условию. Один оператор WHERE заменяет собой структуру «цикл с вложенным ветвлением».
Например, в программе объявлен массив:
integer :: R(5) = (/ 1, -1, 1, -1, 1 /)
Требуется обнулить все его отрицательные элементы.
Задачу можно решить следующим традиционным способом:
do i = 1, 5
if(R(i) < 0) R(i) = 0
end do
С помощью оператора WHERE задача решается так:
where(R <0) R=0
Смысл следующий: всем элементам массива R, меньшим нуля, присвоить ноль.
Существует также конструкция WHERE-ELSEWHER-ENDWERE. Например, в том же самом массиве требуется занулить отрицательные и удвоить все остальные элементы. Программа будет следующей:
where(R < 0)
R = 0
elsewhere
R=2*R
end where
Типовые задачи обработки массива
Пример 1. Вычисление среднего значения. Дана таблица среднемесячных температур в течение года: T(1:12) – одномерный вещественный массив. Требуется вычислить среднегодовую температуру, а также ежемесячные отклонения от этой величины.
Program Example
Integer, parameter:: N=12
Real T(N), Dt(N), St
Integer i
! Ввод исходных данных
print *,'Вводите таблицу температур'
do i= 1, N
write(*,’(I3,a,\)’) i,’:’
Read *,T(i)
enddo
!Вычисление средней температуры
St = 0;
do i= 1, N
St = St + T[i]
enddo
St=St/N;
!Вычисление таблицы отклонений от среднего
do i= 1, N
Dt(i)= St – T(i)
enddo
!Вывод результатов
print *,' Средняя температура равна ', St
print*, 'Отклонения от средней температуры:'
do i= 1, N
print ‘(I3,A,F6.2)’, i, ':', Dt(i)
enddo
End program Example
По этой программе можно рассчитать среднее значение и вектор отклонений от среднего для любого одномерного вещественного массива. Настройка на размер массива осуществляется только редактированием значения константы N.
Пример 2. Выбор максимального элемента. Пусть из рассмотренного выше массива температур требуется отобрать самую высокую температуру и номер месяца, ей соответствующий. Идея алгоритма решения этой задачи: чтобы получить максимальную температуру в вещественной переменной TMax, сначала в нее заносится первое значение массива – элемент T(1). Затем поочередно сравнивается значение TMax с остальными элементами массива температур, и каждое значение, большее, чем TMax, присваивается этой переменной. Для получения номера самого теплого месяца в целой переменной NumMax в нее следует каждый раз засылать номер элемента массива температур одновременно с занесением в TMax его значения.
TMax = T(1)
NumMax = 1
do i= 2, N
If (T(i) > Tmax) Then
TMax = T(i)
NumMax = i
endif
enddo
Заметим, что если в массиве температур несколько значений, равных максимальному, то в NumMax будет получен первый номер из этих элементов. Чтобы получить последнюю дату, нужно в операторе if заменить знак отношения ">" на "> =".
Пример 3. Сортировка массива. В одномерном массиве X из N элементов требуется произвести перестановку значений так, чтобы они расположились по возрастанию, т.е. X1 X2 ... XN.
Существует целый класс алгоритмов сортировки. Ниже описан алгоритм, который называется «метод пузырька».
Идея: производится последовательное упорядочивание смежных пар элементов массива: X1 и X2, X2 и X3,..., XN-1 и XN. В итоге максимальное значение переместится в XN. Затем ту же процедуру повторяют до XN-1 и т.д., вплоть до цепочки из двух элементов X1 и X2. Такой алгоритм будет иметь структуру двух вложенных циклов, причем внутренний цикл – переменной (сокращающейся) длины.
do I=1,N-1
do K = 1,N–I
If (X(K)> X(K+1)then
A=X(K)
X(K)=X(K+1)
X(K+1)=A
Endif
Enddo
enddo
Массивы в процедурах
Массив может быть как аргументом процедуры, так и ее результатом. Рассмотрим пример. Составим процедуру-функцию, вычисляющую евклидову норму вектора. Евклидова норма равна корню квадратному из суммы квадратов элементов вектора.
function Norma(X,L) !параметры: имя и размер массива
real Norma
integer L,i
real X(L) !Описание формального аргумента-массива
Norma=0
Do i=1,L
Norma=Norma+X(i)**2
Enddo
Norma=sqrt(Norma)
End function
Пусть в основной программе присутствует описание:
integer, parameter m=10, n=20
real A(m), B(n), Na, Nb
Далее значения массивов А и В вводятся или вычисляются. Вычисление нормы вектора А будет получено в переменной Na, а норма вектора В в переменной Nb в результате выполнения операторов:
Na=Norma(A,m)
Nb=Norma(B,n)
Здесь при каждом вызове процедуры фактическим параметром является массив той же формы, что и массив – формальный параметр. Передаваемые размеры массивов имеют разные значения.
Однако форма ассоциируемых при вызове процедуры массивов фактических и формальных параметров может различаться, что позволяет в ряде случаев упростить написание программы. Такая возможность использована в следующей программе, по которой происходит обмен содержимого двух матриц:
integer, parameter :: n = 5, m = 10, k = m*n
real a(m, n) /k*1.0/, b(m, n) /k*2.0/
call swap(a, b, m, n)
write(*, *) b
end
subroutine swap(x, y, p, q)
integer p, q
real x(p*q), y(p*q) ! x и y – вектора размера p*q
real r(size(x)) ! r – автоматический массив
r = x; x = y; y = r ! функция size(x) определяет
!размер массива x
end subroutine swap
Из данного примера видно, что границы размерностей формального параметра-массива могут задаваться неконстантными выражениями, которые будут вычисляться заново при каждом выполнении процедуры.
К автоматическим объектам (массив r в примере) относятся объекты данных, размеры которых зависят от неконстантных описательных выражений и которые не являются формальными параметрами процедуры.
Встроенные функции для работы с массивами
В Фортране существует множество встроенных функций для работы с массивами. Полный их список имеется в [1], а также в документации, поставляемой с компилятором Фортрана. Приведем здесь описание лишь некоторых часто используемых в вычислительной практике функций.
Функция |
Действие, выполняемое функцией |
SIZE(array[,dim]) |
- возвращает стандартное целое, равное размеру массива array. Если присутствует целый параметр dim – номер измерения массива, то возвращает его протяженность |
MAXLOC(array[,mask][,dim]) |
Возвращает одномерный массив, размер которого равен рангу массива array. Значения элементов массива-результата равны индексам максимального элемента числового массива array; mask – необязательное условие, которому должно удовлетворять значение необязательного элемента. Если несколько элементов содержат максимальное значение, то берется первый по порядку их следования в array. |
MINLOC(array[,mask][,dim]) |
Выполняет те же действия, что и MAXLOC, но для минимального элемента массива |
MAXVAL(array[,dim][,mask]) |
Возвращает максимальное, удовлетворяющее необязательной маске mask значение числового массива array вдоль заданного необязательного измерения dim. |
MINVAL(array[,dim][,mask]) |
Подобен MAXVAL, но ищет минимальный элемент массива |
PRODUCT(array[,dim][,mask]) |
Вычисляет произведение всех элементов массива вдоль необязательного измерения dim; перемножаемые элементы могут отбираться необязательной маской mask |
SUM(array[,dim][,mask]) |
Подобна PRODUCT, но вычисляет сумму элементов массива |
DOT_PRODUCT(vector_a, vector_b) |
Вычисляет скалярное произведение двух одномерных массивов (векторов) vector_a, vector_b |
MATMUL(matrix_a, matrix_b) |
Осуществляет перемножение двух числовых матриц matrix_a, matrix_b |
TRANSPOSE(matrix) |
Транспонирует матрицу (двумерный массив) matrix |
Упражнения
1. Дан вектор {zi}, i = 1,...,50. Вычислить длину этого вектора:
2. Вычислить полином 10-й степени по формуле Горнера:
a10x10 + a9x9 + ... + a1x + a0 = ((...(a10x + a9)x + a8)x + ... + a1)x + a0.
3. Для вектора {xi}, i = 1,...,20 подсчитать количество компонент, значения которых лежат в интервале [0,1].
4. Даны два вектора{xi}, {yi}, i = 1,...,10, упорядоченные по возрастанию. Слить их в один вектор {zi}, i = 1,...,20 так, чтобы сохранилась упорядоченность.
5. Дан массив, состоящий из 100 целых чисел:
а) вывести все числа, которые встречаются в этом массиве несколько раз;
б) вывести все числа, которые встречаются в массиве только по одному разу.
6. В целочисленной матрице размером 10 10 найти значение и индексы максимального элемента. Составить два варианта программы: без использования стандартной функции и с использованием стандартной функции.
7. В двоичной матрице 5 10 определить номер строки с наибольшим количеством нулей.
8. Все строки вещественной матрицы 10 15 упорядочить по убыванию значений их элементов.
9. Транспонировать целочисленную матрицу 5 5, т.е. перевернуть вокруг главной диагонали. Составить два варианта программы: без использования стандартной функции и с использованием стандартной функции.
10. В двоичной матрице 10 10 найти совпадающие строки.
11. Написать программу вычисления скалярного произведения двух векторов в двух вариантах: без использования стандартной функции и с использованием стандартной функции.
12. Написать программу умножения матрицы на вектор в двух вариантах: без использования стандартной функции и с использованием стандартной функции.