Pure functions may be used in expressions in FORALL statements and constructs, unlike general functions. Several examples of this are given below.
! This statement function is pure since it does not reference ! any other functions REAL myexp myexp(x) = 1 + x + x*x/2.0 + x*x*x/6.0 FORALL ( i = 1:n ) a(i) = myexp( a(i+1) ) ... ! Intrinsic functions are always pure FORALL ( i = 1:n ) a(i,i) = log( abs( a(i,i) ) ) Because a forall-assignment may be an array assignment, the pure function can have an array result. Such functions may be particularly helpful for performing row-wise or column-wise operations on an array. The next example illustrates this.
INTERFACE PURE FUNCTION f(x) REAL, DIMENSION(3) :: f, REAL, DIMENSION(3), INTENT(IN) :: x END FUNCTION f END INTERFACE REAL v (3,10,10) ... FORALL (i=1:10, j=1:10) v(:,i,j) = f(v(:,i,j)) A limited form of MIMD parallelism can be obtained by means of branches within the pure procedure that depend on arguments associated with array elements or their subscripts when the function is called from a FORALL. This may sometimes provide an alternative to using sequences of masked FORALL or WHERE statements with their potential synchronization overhead. The next example suggests how this may be done.
REAL PURE FUNCTION f (x, i) REAL, INTENT(IN) :: x ! associated with array element INTEGER, INTENT(IN) :: i ! associated with array subscript IF (x > 0.0) THEN ! content-based conditional f = x*x ELSE IF (i==1 .OR. i==n) THEN ! subscript-based conditional f = 0.0 ELSE f = x ENDIF END FUNCTION
REAL a(n) INTEGER i ... FORALL (i=1:n) a(i) = f( a(i), i) Because pure procedures have no constraints on their internal control flow (except that they may not use the STOP statement), they also provide a means for encapsulating more complex operations than could otherwise be nested within a FORALL. For example, the fragment below performs an iterative algorithm on every element of an array. Note that different amounts of computation may be required for different inputs. Some machines may not be able to take advantage of this flexibility.
PURE INTEGER FUNCTION iter(x) COMPLEX, INTENT(IN) :: x COMPLEX xtmp INTEGER i i = 0 xtmp = -x DO WHILE (ABS(xtmp).LT.2.0 .AND. i.LT.1000) xtmp = xtmp * xtmp - x i = i + 1 END DO iter = i END FUNCTION
... FORALL (i=1:n, j=1:m) ix(i,j) = iter(CMPLX(a+i*da,b+j*db))