Previous | Table of Contents | Next |
1.2.15.7. Indexed Parallel Array AssignmentThe 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:
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 |