Introducing arrays
4.4 Array sections
We have so far considered arrays whose elements are labelled by integers (“subscripts”)ranging from 1 up to the maximum extent in each dimension. However, subscripts may run from starting points other than 1 with a notation where both the lower and upper subscript limits are given, separated by a colon. For example,
REAL :: annual(1900:2025)
declares an array with 126 elements, i.e. annual(1900), annual(1901), annual(1902),…, annual(2025). In a case like this items such as annual (1) simply do not exist. This notation can equally well be used for multidimensional arrays, as in
LOGICAL :: flipper(–10:10,32,0:20)
which is a rank-three array with total size 21 × 32 × 21.
The colon notation is also used to refer to what is called an “array section”, which is a subset of a previously declared array. We could have
REAL :: annual(1900:2025), decade(10) .
.
.
decade = annual(1981:1990)
where, in the assignment statement, annual (1981:1990) is an array section, i.e. a particular set of ten elements from the larger array annual. The elements of the array decade are being set equal to annual (1981), annual (1982),…, annual (1990). In fact, for array sections, the notation can be extended to allow sets of elements that are not sequential in the original array, by specifying a “stride” after a second colon.
So,
annual(1904:1996:4)
is an array section consisting of every fourth element starting from annual(1904) and going up to annual (1996). The three bracketed numbers, separated by colons, are a “subscript triplet” and the general rule is that the processor starts from the first and moves on to the second in steps equal to the third. If leaps is a rank-one real array of size 24, then
leaps = annual(1904:1996:4)
picks out leap years. The stride may be negative and, if it is equal to –1, the effect is to give an array section with elements in the reverse order from the original array. Note that sections of the same array may occur on both sides of an assignment statement, as in
decade = decade(10:1:–1)
which reverses the order of the elements in decade, or tenfold = tenfold + tenfold(10:1:–1)
where tenfold is a rank-one array of size 10. This array assignment statement is a bit like tenfold(1) = tenfold(1) + tenfold(10)
tenfold(2) = tenfold(2) + tenfold(9) .
. .
tenfold(10) = tenfold(10) + tenfold(1)
except for the very important difference that when we write it out the long way, with ten scalar assignment statements, the last five statements will have quantities on the right-hand side that were changed by the first five statements. The array assignment statement, on the other hand, always uses the original values of all the
elements on the right-hand side and the result is therefore not dependent on the order in which a processor might evaluate the elements of the array on the left-hand side.
By applying this notation to each dimension in turn we can form sections of multidimensional arrays.
With the rank-three array given by INTEGER :: matrices(4,4,200) it is possible to have sections such as
matrices(1:4, 1:4, 1) matrices(1:4, 4, 98)
matrices(4:1:–1, 4:1:–1, 1:200)
The first of these fixes the third subscript as 1 and so gives a two-dimensional array with 16 elements in total, i.e. a “size” of 16. In the second case both the second and third subscripts are fixed, leaving a one-dimensional array of size four. The final example is like the full array but with the element order reversed along two of the three dimensions.
In an array section, any subscript limit may be omitted, in which case it is taken to be the array’s lower bound (before the colon) or upper bound (after the colon). So, with the array matrices as above, the examples could be written more compactly:
matrices(:,:,1) matrices(:,4, 98)
matrices (4:1:–1, 4:1:–1,:)
There are some subtleties to the syntax associated with array sections. An array section is an array even if it has only one element or even if it has no elements at all. For example,
r(1:0) = 1.0
is valid but does nothing because the array section on the left has no elements. Bear in mind that an assignment statement can have an array on the left and a scalar on the right. But,
r(1:0) = (/1.0/)
is illegal because on the right we have an array of size one (not a scalar!) which is not conformable with the zero-sized array on the left.
In view of the importance of the subscript triplet notation for array sections, it is stated concisely for future reference in Section 4.6 below.
4.5 Exercises 4.A 4.A
1
Write statements, which should be as concise as possible, to set up the following one-dimensional arrays:
(i) The square roots of the first ten positive integers;
(ii) (/–1,–i,… (repeated30times), 1 , 1,… (repeated30times)/);
(iii) The first ten powers of π.
4.A 2
Write declaration statements to set up two-dimensional arrays to contain examination marks (0–100) and corresponding letter grades (A–F) for each of 300 students in each of 12 subjects. Write code to rescale all the marks so that the average mark is 60 per cent in every subject, and then convert the marks into grades in a sensible way.
4.A 3
Write code to set up a two-dimensional array of the binomial coefficients, i.e. the numbers of ways in which m objects may be selected from n, n being a positive integer up to 50.
4.A 4
A statistical exercise: if xn (n = 1,…, N) is a set of N values drawn from a distribution with mean X and variance a, then estimates of X and a are given by
and the uncertainty in the estimate X is σ/N1/2.
On this basis, write a program to read in a series of numbers that are assumed to come from a distribution having a particular mean. The program is to calculate and write out an estimate, X, of the mean of the distribution, together with the uncertainty in it.
4.6