Fortran array intrinsics
last modified November 14, 2026
Fortran ships with a set of intrinsic functions that treat a whole array as
one value. Some of them reduce an array to a scalar, such as sum
and maxval; others return the position of a value, such as
maxloc and findloc; and a third group rearranges
arrays, such as pack, unpack and spread.
A logical mask selects which elements take part in an operation. Using these
functions instead of hand-written loops makes the intent clear and lets the
compiler vectorise the work.
Sums and products
sum adds the elements of an array and product
multiplies them, both returning a scalar when no dimension is given. With the
dim argument they reduce along one dimension and return an array
of one rank less: sum(m, dim=1) adds down the columns of a matrix,
and sum(m, dim=2) adds across its rows. minval and
maxval work the same way and return the smallest and largest
values.
program i1
implicit none
integer :: a(5)
integer :: m(2, 3)
a = [4, 8, 15, 16, 23]
m = reshape([1, 2, 3, 4, 5, 6], [2, 3])
print *, 'sum: ', sum(a)
print *, 'product:', product(a(1:4))
print *, 'minval: ', minval(a)
print *, 'maxval: ', maxval(a)
print *, 'sum of m: ', sum(m)
print *, 'sum along dim 1:', sum(m, dim=1)
print *, 'sum along dim 2:', sum(m, dim=2)
end program i1
The five values add to 66, and the product of the first four is 7680. The smallest value is 4 and the largest is 23. The matrix holds the numbers 1 to 6, so its total is 21. Summing along dimension 1 gives one result per column, 3, 7 and 11, and summing along dimension 2 gives one result per row, 9 and 12.
$ gfortran i1.f90 -o i1 $ ./i1 sum: 66 product: 7680 minval: 4 maxval: 23 sum of m: 21 sum along dim 1: 3 7 11 sum along dim 2: 9 12
Locations of extremes
minloc and maxloc return the subscripts of the
smallest and largest element instead of the values. For a rank-one array the
result is a one-element array, and with dim it becomes an array of
the positions along that dimension. findloc searches for a given
value and returns its first position, or zero when the value is absent. All
three count from the declared lower bound, which matters when the array does
not start at 1.
program i2
implicit none
integer :: a(6)
integer :: m(2, 3)
a = [7, 3, 9, 3, 9, 1]
m = reshape([5, 2, 8, 1, 6, 4], [2, 3])
print *, 'minloc:', minloc(a)
print *, 'maxloc:', maxloc(a)
print *, 'findloc 9:', findloc(a, 9)
print *, 'findloc 5:', findloc(a, 5)
print *, 'maxloc of m: ', maxloc(m)
print *, 'maxloc dim 1: ', maxloc(m, dim=1)
print *, 'maxloc dim 2: ', maxloc(m, dim=2)
end program i2
The smallest value in a is 1, at position 6, and the largest is
9, which first appears at position 3, so that is the answer even though 9
occurs again later. The same rule gives 3 for findloc(a, 9), while
findloc(a, 5) returns 0 because 5 is not in the array. In the
matrix the maximum is 8 at row 1, column 2; the matrix form of the result
prints both subscripts. With dim=1 every column has its maximum in
row 1, and with dim=2 the two rows have their maxima in columns 2
and 3.
$ gfortran i2.f90 -o i2 $ ./i2 minloc: 6 maxloc: 3 findloc 9: 3 findloc 5: 0 maxloc of m: 1 2 maxloc dim 1: 1 1 1 maxloc dim 2: 2 3
Counting and logical reduction
A comparison between an array and a scalar produces a logical array of the
same shape. count returns how many elements of such a mask are
true, while any and all answer whether at least one
or every element is true. These three functions turn a question about the data
into a single number or a single logical value, and they read almost like the
sentence that states the question.
program i3
implicit none
integer :: a(6)
a = [4, -2, 0, 7, -5, 9]
print *, 'count positive:', count(a > 0)
print *, 'count zero: ', count(a == 0)
print *, 'any negative: ', any(a < 0)
print *, 'all positive: ', all(a > 0)
print *, 'all nonzero: ', all(a /= 0)
end program i3
Three values are positive, 4, 7 and 9, and one is zero. The array contains
negative values, so any(a < 0) is true, but not all values are
positive, so all(a > 0) is false. There is one zero, so
all(a /= 0) is also false. A logical result is printed as
T or F.
$ gfortran i3.f90 -o i3 $ ./i3 count positive: 3 count zero: 1 any negative: T all positive: F all nonzero: F
Masks
Most reduction functions accept a mask argument, a logical array
of the same shape that selects the elements to include. The mask can be built
from any condition, and it is evaluated before the reduction, so the array is
not changed. A mask is the functional equivalent of an if inside a
loop, written as an expression.
program i4
implicit none
integer :: a(6)
a = [4, -2, 0, 7, -5, 9]
print *, 'sum positive:', sum(a, mask=a > 0)
print *, 'sum negative:', sum(a, mask=a < 0)
print *, 'max positive:', maxval(a, mask=a > 0)
print *, 'count > 3: ', count(a > 3)
print *, 'count even: ', count(mod(a, 2) == 0)
end program i4
The positive values 4, 7 and 9 add to 20, and the negatives -2 and -5 add to
-7; the zero belongs to neither mask. The largest positive value is 9. Three
values exceed 3, and three are even, namely 4, -2 and 0. The last mask is
itself an array expression, since mod works element by element,
which shows that a mask is just another logical array.
$ gfortran i4.f90 -o i4 $ ./i4 sum positive: 20 sum negative: -7 max positive: 9 count > 3: 3 count even: 3
Pack, unpack and merge
pack collects the elements selected by a mask into a
one-dimensional array, which is the natural way to extract a subset whose
length is not known in advance. unpack does the reverse: it
scatters a vector into the true positions of a mask and fills the rest with a
given value. merge keeps the shape and chooses between two arrays
element by element. pack shortens, unpack restores a
shape, and merge never changes one.
program i5
implicit none
integer :: a(6)
logical :: mask(6)
a = [4, -2, 0, 7, -5, 9]
mask = [.true., .false., .true., .false., .true., .false.]
print *, 'pack:', pack(a, a > 0)
print *, 'unpack:', unpack([1, 2, 3], mask, 0)
print *, 'merge:', merge(a, 0, a > 0)
end program i5
Packing the positive values gives the vector 4, 7, 9. Unpacking the vector 1,
2, 3 into the alternating mask puts those numbers at positions 1, 3 and 5 and
zero everywhere else, so the result has six elements again. merge
returns 4, 0, 0, 7, 0, 9: the positive elements of a and zero in
the places where the mask is false.
$ gfortran i5.f90 -o i5 $ ./i5 pack: 4 7 9 unpack: 1 0 2 0 3 0 merge: 4 0 0 7 0 9
Reshape and spread
reshape gives an array a new shape, filling it in array element
order, and spread adds a dimension by replicating an array along
it. Spreading a vector of length three with dim=1 and
ncopies=2 produces a 2 by 3 matrix whose two rows are the same;
with dim=2 the result is a 3 by 2 matrix whose two columns are the
same. The two functions are often used to prepare data for matmul
or for output.
program i6
implicit none
integer :: v(6)
integer :: m(2, 3)
integer :: s(2, 3)
integer :: row(3)
v = [1, 2, 3, 4, 5, 6]
row = [10, 20, 30]
m = reshape(v, [2, 3])
s = spread(row, 1, 2)
print *, 'm:'
print *, m
print *, 'spread with dim 1:'
print *, s
print *, 'spread with dim 2:'
print *, spread(row, 2, 2)
end program i6
The reshaped matrix holds the values 1 to 6 in column-major order, as in the previous article. The spread matrix printed in storage order is 10, 10, 20, 20, 30, 30, because each column of the 2 by 3 result contains one value repeated twice. Spreading along dimension 2 gives 10, 20, 30, 10, 20, 30, the same row repeated in both columns.
$ gfortran i6.f90 -o i6
$ ./i6
m:
1 2 3 4 5 6
spread with dim 1:
10 10 20 20 30 30
spread with dim 2:
10 20 30 10 20 30
The where construct
where applies an assignment to the elements of an array for which
a mask is true and leaves the others alone. The one-line form handles a single
statement, and the construct with elsewhere handles two or more
branches. All masks are evaluated before any assignment happens, so the result
does not depend on the order in which the elements are processed. It is the
array equivalent of an if inside a loop.
program i7
implicit none
integer :: a(6)
a = [-3, -1, 0, 2, 5, 7]
where (a < 0)
a = 0
elsewhere (a > 0)
a = a * 10
end where
print *, a
end program i7
The negative values become zero, the zero stays zero because no branch matches
it, and the positive values are multiplied by ten. The result is 0, 0, 0, 20,
50 and 70. Writing the same transformation as a loop would need a temporary
copy of the original array if the conditions had to see the old values, while
where guarantees that behaviour by definition.
$ gfortran i7.f90 -o i7
$ ./i7
0 0 0 20 50 70
A complete example
The program below summarises a list of exam scores. It computes the mean with
sum and size, finds the best score and its position
with maxval and maxloc, counts the passing scores
with count, counts the scores above the mean, and extracts the
good scores with pack. Every statistic is one expression over the
whole array.
program i8
implicit none
integer :: scores(8)
real :: mean
scores = [72, 45, 88, 91, 60, 55, 78, 83]
mean = real(sum(scores)) / size(scores)
print *, 'mean: ', mean
print *, 'best: ', maxval(scores), 'at', maxloc(scores)
print *, 'worst: ', minval(scores)
print *, 'passed: ', count(scores >= 60)
print *, 'above mean:', count(scores > mean)
print *, 'good scores:', pack(scores, scores >= 80)
end program i8
The scores add to 572, so the mean is 71.5. The best score is 91 at position
4, and the worst is 45. Six scores are at least 60. Five scores lie above the
mean, namely 88, 91, 78, 83 and 72, and pack collects the four
scores of 80 or more as 88, 91, 83. The real division needs the
real conversion, because sum(scores) / size(scores)
would be an integer division and would give 71.
$ gfortran i8.f90 -o i8 $ ./i8 mean: 71.5000000 best: 91 at 4 worst: 45 passed: 6 above mean: 5 good scores: 88 91 83
Next steps
The next article, Fortran allocatable
arrays, gives arrays a size that is decided at run time, which is often
needed before pack or findloc can be used on real
data. The Fortran arrays article explains the
constructors and sections used here, and the
array arguments article shows how to
pass these arrays to procedures. The
intrinsic numeric functions article
covers the scalar functions that where and the masks rely on.
Source
Fortran 2018 standard (J3/18-007r1)
In this article we have reduced arrays with sum,
product, minval and maxval, located
values with maxloc, minloc and
findloc, tested them with count, any and
all, selected elements with masks, pack,
unpack and merge, changed their shape with
reshape and spread, and applied conditional
assignments with where.
Author
List all Fortran tutorials.