Fortran 90 (F90) is a complex language. It augments Fortran 77 (F77)
with pointers, user-defined datatypes, modules, recursive
subroutines, dynamic storage allocation, array operations, new
intrinsic functions, and many other features. We focus
here on those new features that are most relevant to parallel
programming: the * array assignment statement
* and the
* array intrinsic functions*.

F90 allows a variety of * scalar
* operations---operations
defined on single values---to be applied also to entire
arrays. This feature causes the scalar operation to be applied to each
element of the array. If an operation involves several values, all
must be represented by * conformable
* arrays, that is, scalar
values or arrays of the same size and shape. The operation is
performed on corresponding elements from each array. For example,
consider the following scalar operation, which assigns the sum `
b+c` to ` a`.

integer a, b, c a = b + c

In F90, we can apply the same operation to arrays ` A` and ` B`
and scalar ` c`, as follows. This assigns each element `
A(i,j)` of ` A` the sum ` B(i,j)+c`.

integer A(10,10), B(10,10), c A = B + c

In fact, all F90's unary and binary intrinsic operations can be applied to arrays, as the following examples show.

real A(10,20), B(10,20)

logical L(10,20)

A = A + 1.0! Adds1.0to each element ofA

A = SQRT(A)! Computes square root of each element ofA

L = A .EQ. B! SetsL(i,j)to.true.ifA(i,j)=B(i,j);! and to

.false.otherwise

A conformable * array section
* can be substituted for an entire
array in an array operation. An array section is represented by
specifying a range for one or more subscripts. A range is represented
by a triplet that has the following general form.
* lower-bound* : * upper-bound* : * stride*

A stride of 1 is assumed if ` : stride
` is omitted, and
bounds can be omitted if the corresponding bounds of the array are
required. See Figure 7.1 for examples of array
sections.

**Figure 7.1:** * F90 array sections. The three examples show array sections comprising (a) all of
row 2, (b) elements 2..7 of row 2, and (c) elements
1,3,5,7 of row 2,
respectively.*

When operations are performed on arrays and array sections, corresponding
elements are selected by position, not index. Hence, different array
components do not need to have corresponding subscripts, and we can
write the following code to compute the sum ` A(i)=B(i)+B(i+1)` for
` 1i7` (Figure 7.2).

` A(1:7) = B(1:7) + B(2:8)`

**Figure 7.2:** * Use of array sections to compute the sum B(i)+B(i+1)
for 1i7.*

Finally, a masked array assignment uses the ` WHERE` construct to
restrict the array elements on which an assignment is performed. For
example, the following statement replaces each nonzero element of
` X` with its reciprocal (the F90 ` /=` operator is equivalent
to ` .NE.` in F77).
` WHERE(X /= 0) X = 1.0/X`

All F90 intrinsic functions that apply to scalar values can also be
applied to arrays, in which case the function is applied to each array
element. For example, ` ABS(A)` returns an array containing the
absolute values of the elements of array ` A`. In addition, F90
provides a number of * transformational
* functions which
return a scalar or array result that depends on the values of many
elements of an array. Table 7.1 lists a
representative selection of these functions.

**Table 7.1:** Selected F90 array intrinsic functions.

` MAXVAL`, ` MINVAL`, ` SUM`, and ` PRODUCT` perform a
reduction operation (Section 2.3.2) on an array,
returning a scalar value representing the maximum, minimum, sum, or
product of the elements of the array, respectively. Hence, the
following code sets the scalar variable ` s` to the sum of the
elements of the array ` X`.

real s, X(100) s = SUM(X)

**Figure 7.3:** * The F90 CSHIFT function. In (a), a negative shift of
one element is applied in dimension 1; in (b), a negative shift of
three elements is applied in dimension 2.*

The ` CSHIFT` function performs a circular shift on an array,
returning a new array of the same size and shape but with its elements
in a different configuration. As illustrated in
Figure 7.3, a call of the form
` CSHIFT(A,s,d)`

performs a circular shift on the elements of the array ` A`, where
the scalar or array ` s` specifies the size and direction (left is
positive) of the shift and the optional argument ` d` indicates the
dimension in which the shift is to be applied (it defaults to 1).
This function is often used in expressions involving index
expressions. For example, consider the following F77 loop.

real X(0:99), B(0:99) do i = 0,99 B(i) = ( X(mod(i+99,100) + X(mod(i+1,100)) )/2 enddoThis can be written in F90 as

real X(100), B(100), L(100), R(100) L = CSHIFT(X,+1) R = CSHIFT(X,-1) B = ( L + R )/2or simply as follows.

real X(100), B(100) B = ( CSHIFT(X,+1) + CSHIFT(X,-1) )/2In both cases, an array assignment sets the array

Although powerful, F90's array operations can be used to implement only a limited class of data-parallel algorithms. Consequently, F90 programs often incorporate code that, although implicitly parallel, must be executed sequentially if a compiler is unable to detect the implicit parallelism. For example, the following code zeroes the diagonal of an array. Although clearly a parallel operation, this cannot be expressed as such using the F90 array assignment statement.

do i = 1,100 X(i,i) = 0.0 enddo

Program 7.1 illustrates F90's array assignment and array
intrinsics. This program, for which both F77 and F90 versions are
given, first applies a five-point finite difference stencil to the
array ` X` to obtain the array ` New` and then computes the
maximum difference between the two arrays. The F90 version uses an
array assignment and the intrinsic functions ` ABS` and `
MAXVAL`.