Previous Table of Contents Next


1.2.15.7. Indexed Parallel Array Assignment—The forall Construct

The forall construct provides a mechanism to specify an indexed parallel assignment of values to an array for the following sorts of formulas often found in mathematical treatises:

   aij = i + j, for i = 1 to n, j = 1 to m

or

   aii = bi, for i = 1 to n

The first formula can be translated into nested do loops:

   do j = 1, m
      do i = 1, n
         a(i,j) = i + j
      end do
   end do

This formulation does not allow for the optimization that can be achieved on some computers when array notation is used.

The forall statement makes use of array element and section references to express such calculations more naturally and at the same time indicate computations that may be executed in parallel:

   forall (i=1:n, j=1:m)
      a(i,j) = i+j
   end forall

The second formula cannot be expressed with array section notation, but a forall statement can be used to assign the elements of the array b of rank one to the diagonal of array a:

   forall (i=1:n)
      a(i,i) = b(i)
   end forall

The following are permitted in a forall body:

  Assignment statements
  Pointer assignment statements
  where constructs
  forall constructs

The forall statement resembles a loop construct, but its evaluation rules treat the statements within the construct as indexed parallel operations, in which a particular statement is executed for all selected index values before the next statement in the forall body is executed. As such, it is not a control construct, but a special kind of parallel assignment statement. On the other hand, a do construct executes each statement in its range in order for a particular index value and then returns to the first statement in the range to repeat the computations for the next index value.

Sometimes it is desirable to exclude some elements from taking part in a calculation. Thus, an optional mask expression may appear in a forall header:

   forall (i=1:n, j=1:m, a(i)<9.0 .and. b(j)<9.0)
      c(i,j) = a(i) + b(j)
   end forall

1.2.15.8. Calculating Probabilities

Consider the problem of calculating the probability that a throw of two dice will yield a 7 or an 11. The resulting program uses the built-in subroutine random_number to generate random numbers between 0 and 1.

When the argument to the built-in subroutine random_number is a real array, the array is filled with a collection of real numbers each greater than or equal to 0 and less than 1. The subroutine random_int, which calls random_number, returns an array of integers from low to high:

   module random_module

   public :: random_int

   contains

   subroutine random_int (value, low, high)

      integer, dimension (:), intent (out) :: value
      integer, intent (in) :: low, high
      real, dimension (:), allocatable :: uniform_random_value

      allocate (uniform_random_value (size (value)))
      call random_number (uniform_random_value)
      value = int ((high - low + 1) * uniform_random_value + low)
      deallocate (uniform_random_value)

   end subroutine random_int

   end module random_module

   program seven_11

      use random_module
      integer, parameter :: number_of_rolls = 1000
      integer, dimension (number_of_rolls) :: dice, die_1, die_2
      integer :: wins

      call random_int (die_1, 1, 6)
      call random_int (die_2, 1, 6)
      dice = die_1 + die_2
      wins = count ((dice == 7) .or. (dice == 11))

      print “(a, f6.2)”, &
         “The percentage of rolls that are 7 or 11 is”,    &
         100.0 * real (wins) / real (number_of_rolls)

   end program seven_11

The built-in function count returns the number of true values in any logical array; in this case, the value in the array is true if the corresponding value in the array dice is 7 or 11.


Previous Table of Contents Next