Fortran 90 Tutorial_3 by stariya

VIEWS: 11 PAGES: 51

									REPETITIVE EXECUTION

SELECT THE TOPICS YOU WISH TO REVIEW:
  Repetitive Execution

          Counting DO-Loop      Programming Examples:

         Counting Positive and Negative Input Values

         Computing Arithmetic, Geometric and Harmonic Means

         Computing Factorial

          General DO-Loop with EXIT      Programming Examples:

         Determining the Minimum and Maximum of Input Data

         Computing the Square Root of a Positive Number

         Computing EXP(x)

         Computing the Greatest Common Divisor of Two Positive Integers

         Checking If a Positive Integer Is a Prime Number

          Nested DO-Loop      Programming Examples:

         Computing Classes Averages

         Computing a Set of Values of EXP(x)

         Armstrong Numbers

         Finding All Primes in the Range of 2 and N

         Finding all Prime factors of a Positive Integer

          Handling End of File: the READ Statement Revisited

         Computing Arithmetic, Geometric and Harmonic Means: Revisited

          The DO-CYCLE Construct and a Programming Example (Optional)

          Download my course overheads
COUNTING DO-LOOP


There are two forms of loops, the counting loop and the general loop. The syntax of the counting
loop is the following:

DO control-var = initial-value, final-value, [step-size]
     statements
END DO
where control-var is an INTEGER variable, initial-value and final-value are two INTEGER expressions, and step-size
is also an INTEGER expression whose value cannot be zero. Note that step-size is optional. If it is omitted, the
default value is 1. statements is a sequence of statements and is usually referred to as the body of the DO-loop.
You can use any executable statement within a DO-loop, including IF-THEN-ELSE-END IF and even another DO-
loop.

The following are a few simple examples:

       INTEGER variables Counter, Init, Final and Step are control-var, initial-value, final-value and step-size,
        respectively.

        INTEGER :: Counter, Init, Final, Step

        READ(*,*) Init, Final, Step
        DO Counter = Init, Final, Step
           .....
        END DO

       INTEGER variables i is the control-var. The initial-value and final-value are computed as the results of
        INTEGER expressions Upper-Lower and Upper+Lower, respectively. Since step-size is omitted, it is
        assumed to be 1.

          INTEGER :: i, Lower, Upper

         Lower = ....
         Upper = ....
         DO i = Upper - Lower, Upper + Lower
              .....
         END DO
The meaning of this counting-loop goes as follows:

       Before the DO-loop starts, the values of initial-value, final-value and step-size are computed exactly
        once. More precisely, during the course of executing the DO-loop, these values will not be re-
        computed.
       step-size cannot be zero.
       If the value of step-size is positive (i.e., counting up):
             1. The control-var receives the value of initial-value
             2. If the value of control-var is less than or equal to the value of final-value, the statements part is
                  executed. Then, the value of step-size is added to the value of control-var. Go back and
                  compare the values of control-var and final-value.
            3.   If the value of control-var is greater than the value of final-value, the DO-loop completes and
                 the statement following END DO is executed.
      If the value of step-size is negative (i.e., counting down):
            1. The control-var receives the value of initial-value
            2. If the value of control-var is greater than or equal to the value of final-value, the statements
                 part is executed. Then, the value of step-size is added to the value of control-var. Go back and
                 compare the values of control-var and final-value.
            3. If the value of control-var is less than the value of final-value, the DO-loop completes and the
                 statement following END DO is executed.



EXAMPLES

      In the following, the control-var is Count. It receives -3 before the loop starts. It goes down the loop
       body and display the values of Count, Count*Count and Count*Count*Count. Thus, -3, 9, -27 are
       displayed. Then, 2 is added to Count changing its value from -3 to -1. Since this new value of Count (=-1)
       is less than the final-value, the loop body is executed and displays -1, 1, -1. Then, 2 is added to Count
       again, changing the value of Count to 1(=(-1)+2). Since this new value is still less than the final-value,
       the loop body is executed again. This time, it will display 1, 1, 1. Then, 2 is added to Count the third
       time, changing its value to 3. Since 3 is still less than the final-value, 3, 9, 27 are displayed. After adding
       2 to the value of Count the fourth time, the new value of Count is finally greater than the final-value
       and the DO-loop completes.

           INTEGER     :: Count

           DO Count = -3, 4, 2
              WRITE(*,*) Count, Count*Count, Count*Count*Count
           END DO

      In the following, since steps-size is omitted, it is assumed to be 1. Therefore, the control-var Iteration
       receives 3, 4, and 5 in this order.

       INTEGER, PARAMETER :: Init = 3, Final = 5
       INTEGER            :: Iteration

       DO Iteration = Init, Final
          WRITE(*,*) 'Iteration ', Iteration
       END DO

      The following uses two Fortran intrinsic functions MIN() and MAX(). It is a count-down loop. The initial-
       value is the maximum of a, b and c, the final-value is the minimum of a, b and c, and the step-size is -2.
       Therefore, if the READ statement reads 2, 7, 5 into a, b and , then MAX(a,b,c) and MIN(a,b,c) are 7 and
       2, respectively. As a result, control-var List will have values 7, 5, and 3.

           INTEGER :: a, b, c
           INTEGER :: List

           READ(*,*) a, b, c
           DO List = MAX(a, b, c), MIN(a, b, c), -2
              WRITE(*,*) List
           END DO
FREQUENTLY USED LOOP TRICKS
In addition to repeatedly processing some data as shown above, the DO-loop has some other uses as presented
in the following examples:

       Adding numbers: Suppose the value of INTEGER variable Number has been given elsewhere, perhaps
        with a READ. The following code reads in Number integers and computes their sum into variable Sum.

          INTEGER :: Count, Number, Sum, Input

          Sum = 0
          DO Count = 1, Number
             READ(*,*) Input
             Sum = Sum + Input
          END DO

        Sum is initialized to zero. For each iteration, the value of Input, which is read in with READ, is added to
        the value of Sum.

        For example, if the value of Number is 3, and the three input values are 3, 6, and 8
        (on different lines), then the final value of Sum is 17 = 3+6+8. Let us look at it
        closely. Initially, Count receives a value of 1. Since 1 is less than the value of
        Number (=3), the loop body is executed. The READ statement reads the first input
        value 3 into Input and this value is added to Sum, changing its value from 0 to 1
        (=0+1). Now, END DO is reached and the step-size (=1) is added to Count. Hence,
        the new value of Count is 2.

        Since Count is less than Number, the second input value is read into Input. Now,
        Input holds 6. Then, 6 is added to the value of Sum, changing its value to 9 (=3+6).
        The next iteration reads in 8 and adds 8 to Sum. The new value of Sum becomes 17
        (=9+8).

        A simple modification can compute the average of all input numbers:

        INTEGER :: Count, Number, Sum, Input
        REAL    :: Average

        Sum = 0
        DO Count = 1, Number
           READ(*,*) Input
           Sum = Sum + Input
        END DO
        Average = REAL(Sum) / Number

        The above seems obvious. But, please note the use of the function REAL() that converts an INTEGER to a
        REAL. Without this conversion, Sum /Number is computed as dividing an integer by an integer, yielding
        an integer result. Consult singe mode arithmetic expressions for details.
       Factorial: A simple variation could be used to compute the factorial of a positive integer. The factorial
        of an integer N, written as N!, is defined to be the product of 1, 2, 3, ..., N-1, and N. More precisely, N! =
        N*(N-1)*(N-2)*...*3*2*1.

        INTEGER :: Factorial, N, I

        Factorial = 1
        DO I = 1, N
           Factorial = factorial * I
        END DO

        In the above, the DO-loop iterates N times. The first iteration multiplies Factorial with 1, the second
        iteration multiplies Factorial with 2, the third time with 3, ..., the i-th time with I and so on. Therefore,
        the values that are multiplied with the initial value of Factorial are 1, 2, 3, ..., N. At the end of the DO,
        the value of Factorial is 1*2*3*...*(N-1)*N.




SOME HELPFUL NOTES
There are certain things you should know about DO-loops.

       The step-size cannot be zero. The following is not a good practice:

        INTEGER :: count

        DO count = -3, 4, 0
           ...
        END DO

       Do not change the value of the control-var. The following is not a good practice:

        INTEGER :: a, b, c

        DO a = b, c, 3
           READ(*,*) a ! the value of a is changed
           a = b-c     ! the value of a is changed
        END DO

       Do not change the value of any variable involved in initial-value, final-value and step-size. The following
        is not a good practice:

        INTEGER :: a, b, c, d, e

        DO a = b+c, c*d, (b+c)/e
           READ(*,*) b           ! initial-value is changed
           d = 5                 ! final-value is changed
           e = -3                ! step-size is changed
        END DO

       When you have a count-down loop, make sure the step-size is negative. If you have a positive step-size,
        the body of the DO-loop will not be executed. See the way of executing a DO loop above. The body of
        the following DO will not be executed.
         INTEGER :: i

         DO i = 10, -10
            .....
         END DO

        While you can use REAL type for control-var, initial-value, final-value and step-size, it would be better
         not to use this feature at all since it may be dropped in future Fortran standard. In the DO-loop below, x
         successively receives -1.0, -0.75, -0.5, -0.25, 0.0, 0.25, 0.5, 0.75 and 1.0.

         REAL :: x

         DO x = -1.0, 1.0, 0.25
            .....
         END DO

         You should not use this form of DO-loop in your programs. See the discussion of general DO for the
         details.


COUNTING POSITIVE AND NEGATIVE INPUT VALUES

PROBLEM STATEMENT

Given a set of integer input values, write a program to count the number of positive and negative
values and compute their sums.

The input is organized as follows:

        The first line gives the number of data values that follow
        Starting with the second line, each line contains an integer input value

For example, the following input shows that there are seven input values (i.e., the 7 on the first line), -6, 7, 2, -9, 0,
8 and 0.
7
-6
7
2
-9
0
8
0


SOLUTION
!   ---------------------------------------------------------
!   This program counts the number of positive and negative
!   input values and computes their sums.
!   ---------------------------------------------------------
PROGRAM Counting
   IMPLICIT NONE

    INTEGER     ::   Positive, Negative
    INTEGER     ::   PosSum, NegSum
    INTEGER     ::   TotalNumber, Count
    INTEGER     ::   Data

    Positive     =   0                             !   # of positive items
    Negative     =   0                             !   # of negative items
    PosSum       =   0                             !   sum of all positive items
    NegSum       =   0                             !   sum of all negative items

    READ(*,*) TotalNumber           ! read in # of items
    DO Count = 1, TotalNumber       ! for each iteration
       READ(*,*) Data               !    read an item
       WRITE(*,*) 'Input data ', Count, ': ', Data
       IF (Data > 0) THEN           !    if it is positive
           Positive = Positive + 1  !         count it
           PosSum   = PosSum + Data !         compute their sum
       ELSE IF (Data < 0) THEN      !    if it is negative
           Negative = Negative + 1  !         count it
           NegSum   = NegSum + Data !         compute their sum
       END IF
    END DO

    WRITE(*,*)                               ! display results
    WRITE(*,*)           'Counting Report:'
    WRITE(*,*)           '   Positive items = ', Positive, ' Sum = ', PosSum
    WRITE(*,*)           '   Negative items = ', Negative, ' Sum = ', NegSum
    WRITE(*,*)           '   Zero items     = ', TotalNumber - Positive - Negative
    WRITE(*,*)
    WRITE(*,*)           'The total of all input is ', Positive + Negative

END PROGRAM Counting
Click here to download this program.




PROGRAM INPUT AND OUTPUT
If the data shown above is stored in a file, say data.in and the above program is compiled to an executable count,
then executing

count < data.in
will generate the following output:

Input   data    1:   -6
Input   data    2:   7
Input   data    3:   2
Input   data    4:   -9
Input   data    5:   0
Input   data    6:   8
Input   data    7:   0

Counting Report:
    Positive items = 3 Sum = 17
    Negative items = 2 Sum = -15
    Zero items     = 2

The total of all input is 5


DISCUSSION
In the program, Positive and Negative are used to count the number of positive and negative data items, and
PosSum and NegSum are used to compute their sums. The program first reads the number of input items into
TotalNumber and uses it as the final value in a DO-loop.

This loop iterates TotalNumber times. For each iteration, it reads in a new data into Data. The
IF-THEN-ELSE-END IF statement tests to see if it is positive or negative, adds 1 into the
corresponding counter, and adds the value into the corresponding sum. Note that the number of
zero items are not counted, since TotalNumber - Positive - Negative gives the number of zero
items. The sum of all zero items are not calculated either, since it must be zero!

COMPUTING ARITHMETIC, GEOMETRIC AND HARMONIC MEANS

PROBLEM STATEMENT

The arithmetic mean (i.e., average), geometric mean and harmonic mean of a set of n numbers
x1, x2, ..., xn are defined as follows:




Since computing geometric mean requires taking square root, it is further required that all input
data values must be positive. As a result, this program must be able to ignore those non-positive
items. However, this may cause all input items ignored. Therefore, before computing the means,
this program should have one more check to see if there are valid items.


SOLUTION
!   ----------------------------------------------------------
!   This program reads a series of input data values and
!   computes their arithmetic, geometric and harmonic means.
!   Since geometric mean requires taking n-th root, all input
!   data item must be all positive (a special requirement of
!   this program , although it is not absolutely necessary).
!   If an input item is not positive, it should be ignored.
!   Since some data items may be ignored, this program also
! checks to see if no data items remain!
! ----------------------------------------------------------

PROGRAM   ComputingMeans
   IMPLICIT NONE

    REAL        ::   X
    REAL        ::   Sum, Product, InverseSum
    REAL        ::   Arithmetic, Geometric, Harmonic
    INTEGER     ::   Count, TotalNumber, TotalValid

    Sum              =   0.0                              !   for the sum
    Product          =   1.0                              !   for the product
    InverseSum       =   0.0                              !   for the sum of 1/x
    TotalValid       =   0                                !   # of valid items

    READ(*,*) TotalNumber                  ! read in # of items
    DO Count = 1, TotalNumber              ! for each item ...
       READ(*,*) X                         ! read it in
       WRITE(*,*) 'Input item ', Count, ' --> ', X
       IF (X <= 0.0) THEN                  ! if it is non-positive
           WRITE(*,*) 'Input <= 0. Ignored'     ! ignore it
       ELSE                                ! otherwise,
           TotalValid = TotalValid + 1     ! count it in
           Sum        = Sum + X            ! compute the sum,
           Product    = Product * X        ! the product
           InverseSum = InverseSum + 1.0/X      ! and the sum of 1/x
       END IF
    END DO

    IF (TotalValid > 0) THEN             ! are there valid items?
       Arithmetic = Sum / TotalValid     ! yes, compute means
       Geometric = Product**(1.0/TotalValid)
       Harmonic   = TotalValid / InverseSum

       WRITE(*,*)          'No. of valid items --> ', TotalValid
       WRITE(*,*)          'Arithmetic mean    --> ', Arithmetic
       WRITE(*,*)          'Geometric mean     --> ', Geometric
       WRITE(*,*)          'Harmonic mean      --> ', Harmonic
    ELSE                                         ! no, display a message
       WRITE(*,*)          'ERROR: none of the input is positive'
    END IF

END PROGRAM ComputingMeans
Click here to download this program.




PROGRAM INPUT AND OUTPUT
This program uses the same format of input as discussed in previous example. More precisely, the first line gives
the number of data items, followed by that number of input line on each which is a data value. Except for the first
input value, which gives the number of input, all other values are real numbers.

       If the input data is
           5
     1.0
     2.0
     3.0
     4.0
     5.0

    it will generate the following output. In this input, all data values are positive and none of them is ignored.

    Input    item    1   -->   1.
    Input    item    2   -->   2.
    Input    item    3   -->   3.
    Input    item    4   -->   4.
    Input    item    5   -->   5.

    No. of valid items              -->   5
    Arithmetic mean                 -->   3.
    Geometric mean                  -->   2.6051712
    Harmonic mean                   -->   2.18978071

   In the following input, the fourth value is negative.
      6
      1.0
      2.0
      3.0
      -4.0
      5.0
      6.0

    The output is shown below:

    Input    item 1      --> 1.
    Input    item 2      --> 2.
    Input    item 3      --> 3.
    Input    item 4      --> -4.
    Input    <= 0.       Ignored
    Input    item 5      --> 5.
    Input    item 6      --> 6.

    # of items read -->              6
    # of valid items ->              5
    Arithmetic mean -->              3.4000001
    Geometric mean -->               2.82523465
    Harmonic mean   -->              2.27272725

   Now, let us try the following input in which all values are non-positive:
     4
     -1.0
     -2.0
     0.0
     -3.0
        We shall get the following output. The program correctly detects there is no valid data values and displays
        a message.

        Input    item 1     --> -1.
        Input    <= 0.      Ignored
        Input    item 2     --> -2.
        Input    <= 0.      Ignored
        Input    item 3     --> 0.E+0
        Input    <= 0.      Ignored
        Input    item 4     --> -3.
        Input    <= 0.      Ignored

        ERROR: none of the input is positive


DISCUSSION
This example is quite simple and does not require further explanation.




COMPUTING FACTORIAL

PROBLEM STATEMENT

The factorial of a non-negative integer n, written as n!, is defined as follows:




Write a program that reads in an integer and computes its factorial. This program should detect if
the input is negative and display an error message.


SOLUTION
!   ----------------------------------------------------------
!   Given a non-negative integer N, this program computes
!   the factorial of N. The factorial of N, N!, is defined as
!           N! = 1 x 2 x 3 x .... x (N-1) x N
!   and 0! = 1.
!   ----------------------------------------------------------

PROGRAM Factorial
   IMPLICIT NONE

    INTEGER :: N, i, Answer
    WRITE(*,*)        'This program computes the factorial of'
    WRITE(*,*)        'a non-negative integer'
    WRITE(*,*)
    WRITE(*,*)        'What is N in N! --> '
    READ(*,*)         N
    WRITE(*,*)

    IF (N < 0) THEN                 ! input error if N < 0
       WRITE(*,*) 'ERROR: N must be non-negative'
       WRITE(*,*) 'Your input N = ', N
    ELSE IF (N == 0) THEN           ! 0! = 1
       WRITE(*,*) '0! = 1'
    ELSE                            ! N > 0 here
       Answer = 1                   ! initially N! = 1
       DO i = 1, N                  ! for each i = 1, 2, ..., N
           Answer = Answer * i      ! multiply i to Answer
       END DO
       WRITE(*,*) N, '! = ', Answer
    END IF

END PROGRAM Factorial
Click here to download this program.




PROGRAM INPUT AND OUTPUT

       If the input is -5, a negative number, the program generates the following output indicating the input is
        wrong.

        This program computes the factorial of
        a non-negative integer

        What is N in N! -->
        -5

        ERROR: N must be non-negative
        Your input N = -5

       If the input is a zero, the output is 0! = 1.

        This program computes the factorial of
        a non-negative integer

        What is N in N! -->
        0

        0! = 1

       If the input is 5, the factorial of 5 is 5!=1*2*3*4*5=120.

        This program computes the factorial of
        a non-negative integer
         What is N in N! -->
         5

         5! = 120

        If the input is 13, the factorial of 15 is 13! = 1*2*3*...*13=1932053504

         This program computes the factorial of
         a non-negative integer

         What is N in N! -->
         13

         13! = 1932053504


DISCUSSION
The basics of writing a factorial computation program has been discussed in a factorial example of counting DO.

It is worthwhile to note that most CPU's do not report integer overflow. As a result, on a typical
computer today, the maximum factorial is around 13!. If you try this program on a PC, you
should get 13! = 1932053504 and 14! = 1278945280. But, 13! > 14! is obviously incorrect.
Then, we have 15! = 2004310016, 16! = 2004189184, and 17! = -288522240. These results are
obviously wrong. This shows that a typical PC can only handle up to 13!

GENERAL DO-LOOP WITH EXIT


The general DO-loop is actually very simple. But, to use it properly, you need to be very careful,
since it may never stop. The general DO-loop has a form as follows:

DO
    statements
END DO
Between DO and END DO, there are statements. These statements are executed over and over without any chance
to get out of the DO-loop. Here is an example,

REAL :: x, y, z
DO
    READ(*,*) x
    y = x*x
    z = x*x*x
    WRITE(*,*) x, ' square = ', y, ' cube = ', z
END DO
One iteration of this loop consists of reading a value for x, computing its square and cube to y and z, respectively,
and displaying the results. Then, the execution goes back to the top and executes the four statements again.
Consequently, this loop is executed over and over and has no chance to stop at all. A loop that never stops is
usually referred to as an infinite loop. To stop the iteration of a DO-loop, we need something else.
THE EXIT STATEMENT
The EXIT is as simple as writing down the word EXIT. It is used to bail out the containing loop.

DO
     statements-1
     EXIT
     statements-2
END DO
In the above, statements-1 is executed followed by the EXIT statement. Once the EXIT statement is reached, the
control leaves the inner-most DO-loop that contains the EXIT statement. Therefore, in the above case, statements-
2 will never be executed.

Since it must be some reason for bailing out a DO-loop, the EXIT statement is usually used with
an IF or even an IF-THEN-ELSE-END IF statement in one of the following forms. Note that
these are not the only cases in which you can use EXIT.

DO
   statements-1
   IF (logical-expression)                EXIT
   statements-2
END DO


DO
    statements-1
    IF (logical-expression) THEN
         statements-THEN
         EXIT
    END IF
    statements-2
END DO
For each iteration, statements in statements-1 are executed, followed the evaluation of the logical-expression. If
the result is .FALSE., statements in statements-2 are executed. This completes one iteration and the control goes
back to the top and executes statements-1 again for next iteration.

If the result of evaluating logical-expression is .TRUE., the first form will executes EXIT,
which immediately stops the execution of the DO-loop. The next statement to be executed is the
one following END DO.

For the second form, if the result of evaluating logical-expression is .TRUE., statements in
statements-THEN are executed followed by the EXIT statement, which brings the execution
to the statement following END DO. Therefore, statements in statements-THEN will do
some "house-keeping" work before leaving the DO-loop. If there is no "house-keeping"
work, the first form will suffice.


EXAMPLES
      The following code reads in values into variable x until the input value becomes negative. All input
       values are added to Sum. Note that the negative one is not added to Sum, since once the code sees
       such a negative value, EXIT is executed.

       INTEGER :: x, Sum

       Sum = 0
       DO
          READ(*,*) x
          IF (x < 0) EXIT
          Sum = Sum + x
       END DO

      The following is an example that "simulates" a counting DO-loop using REAL variables. Variable x is
       initialized to the initial value Lower and serves as a control variable. Before any statement of the DO-
       loop is executed, the value of x is checked to see if it is greater than the final value Upper. If it is, EXIT is
       executed, leaving the loop. Otherwise, the loop body is executed and before goes back to the top, the
       control variable x must be increased by the step size Step. This loop will display -1.0, -0.75, -0.5, -0.25,
       0.0, 0.25, 0.5, 0.75 and 1.0, each of them is on a separate line.

       REAL, PARAMETER :: Lower = -1.0, Upper = 1.0, Step = 0.25
       REAL            :: x

       x = Lower ! initialize the control variable (DON'T FORGET)
       DO
          IF (x > Upper) EXIT   ! is it > final-value?
          WRITE(*,*) x          ! no, do the loop body
          x = x + Step          ! an increase by step-size
       END DO

      In many cases, your program may expect an input satisfying certain conditions. DO-loop can help a lot.
       The following code keeps asking and checking if the input integer value is in the range of 0 and 10
       inclusive. If it is not, the program warns the user and reads again until the input is in the stated range.

       INTEGER :: Input

       DO
          WRITE(*,*) 'Type an integer in the range of 0 and 10 please --> '
          READ(*,*)   Input
          IF (0 <= Input .AND. Input <= 10) EXIT
          WRITE(*,*) 'Your input is out of range. Try again'
       END DO


SOME HELPFUL NOTES

      One of the most commonly seen problem is forgetting to change the logical-expression that may cause
       an EXIT. The following DO-loop never stops and keeps displaying 5, 5, 5, 5, ..., forever. The reason? The
       value of i is never changed.

        INTEGER       :: i

        i = 5
          DO
             IF (i < -2) EXIT
             WRITE(*,*) i
          END DO

         The following is another example:

         INTEGER :: i = 1, j = 5

         DO
            IF (j < 0)         EXIT
            WRITE(*,*)         i
            i = i + 1
         END DO

        Sometimes we just forget to initialize the control-var . We really do not know what would be displayed
         since the value of i is unknown at the beginning of the DO and is certainly unknown after executing i = i
         - 1.

         INTEGER :: i

         DO
            IF (i <= 3) EXIT
            WRITE(*,*) i
            i = i - 1
         END DO



DETERMINING THE MINIMUM AND MAXIMUM OF INPUT DATA

PROBLEM STATEMENT

Suppose we have a set of non-negative input integers terminated with a negative value. These
input values are on separate lines. Write a program to determine the number of input data items,
excluding the negative one at the end, and compute the minimum and the maximum. For
example, the following input contains 7 data values with the seventh being negative. Of the six
non-negative ones, the minimum and maximum are 2 and 9, respectively.

5
3
9
2
7
4
-1


SOLUTION
! ------------------------------------------------------
! This program reads in a number of integer input until
! a negative one, and determines the minimum and maximum
! of the input data values.
! ------------------------------------------------------

PROGRAM MinMax
   IMPLICIT NONE



COMPUTING THE SQUARE ROOT OF A POSITIVE NUMBER

PROBLEM STATEMENT

The square root of a positive number b can be computed with Newton's formula:




where x above starts with a "reasonable" guess. In fact, you can always start with b or some
other value, say 1.

With b and a guess value x, a new guess value is computed with the above formula. This process
continues until the new guess value and the current guess value are very close. In this case, either
one can be considered as an approximation of the square root of b.

Write a program that reads in a REAL value and a tolerance, and computes the square root until
the absolute error of two adjacent guess values is less than the tolerance value.


SOLUTION
!   ---------------------------------------------------------
!   This program uses Newton's method to find the square
!   root of a positive number. This is an iterative method
!   and the program keeps generating better approximation
!   of the square root until two successive approximations
!   have a distance less than the specified tolerance.
!   ---------------------------------------------------------

PROGRAM SquareRoot
   IMPLICIT NONE

    REAL    :: Input, X, NewX, Tolerance
    INTEGER :: Count

    READ(*,*)     Input, Tolerance

    Count = 0                                      ! count starts with 0
    X     = Input                                  ! X starts with the input value
    DO                                             ! for each iteration
       Count = Count + 1                                   !        increase the iteration count
       NewX = 0.5*(X + Input/X)                            !        compute a new approximation
       IF (ABS(X - NewX) < Tolerance)                    EXIT       ! if they are very close, exit
       X = NewX                                            !        otherwise, keep the new one
    END DO

    WRITE(*,*)        'After ', Count, ' iterations:'
    WRITE(*,*)        ' The estimated square root is ', NewX
    WRITE(*,*)        ' The square root from SQRT() is ', SQRT(Input)
    WRITE(*,*)        ' Absolute error = ', ABS(SQRT(Input) - NewX)

END PROGRAM SquareRoot
Click here to download this program.




PROGRAM INPUT AND OUTPUT
If the input are 10.0 for b and 0.00001 for the tolerance, the following output shows that it requires 6 iterations to
reach an approximation of square root of 10. Comparing the result with the one obtained from Fortran intrinsic
function SQRT(), the absolute error is zero.

After 6 iterations:
  The estimated square root is 3.1622777
  The square root from SQRT() is 3.1622777
  Absolute error = 0.E+0

If the input are 0.5 for b and 0.00001 for the tolerance, it takes 4 iterations to reach an
approximation of the square root of 0.5. The value from using Fortran intrinsic function SQRT()
is 0.707106769 and again the absolute error is 0.

After 4 iterations:
  The estimated square root is 0.707106769
  The square root from SQRT() is 0.707106769
  Absolute error = 0.E+0


DISCUSSION

        This program uses X to hold the input value for b and uses NewX to hold the new guess value. The initial
         guess is the input value.
        From the current guess, using Newton's formula, the new guess is compared as
          NewX = 0.5*(X + Input/X)
        Then, the absolute error of X and NewX is computed. If it is less than the tolerance value, EXIT the loop
         and display the results. Otherwise, the current guess is replaced with the new guess and go back for the
         next iteration.




COMPUTING EXP(X)
PROBLEM STATEMENT

The exponential function, EXP(x), is defined to be the sum of the following infinite series:




Write a program that reads in a REAL value and computes EXP() of that value using the series
until the absolute value of a term is less than a tolerance value, say 0.00001.


SOLUTION
!   ---------------------------------------------------------
!   This program computes exp(x) for an input x using the
!   infinite series of exp(x). This program adds the
!   terms together until a term is less than a specified
!   tolerance value. Thus, two values are required:
!   the value for x and a tolerance value. In this program,
!   he tolerance value is set to 0.00001 using PARAMETER.
!   ---------------------------------------------------------

PROGRAM Exponential
   IMPLICIT NONE

     INTEGER               ::   Count             !   # of terms used
     REAL                  ::   Term              !   a term
     REAL                  ::   Sum               !   the sum of series
     REAL                  ::   X                 !   the input x
     REAL, PARAMETER       ::   Tolerance = 0.00001      ! tolerance

     READ(*,*) X                                  !   read in x
     Count = 1                                    !   the first term is 1 and counted
     Sum     = 1.0                                !   thus, the sum starts with 1
     Term = X                                     !   the second term is x
     DO                                           !   for each term
         IF (ABS(Term) < Tolerance)        EXIT   !      if too small, exit
         Sum    = Sum + Term                      !      otherwise, add to sum
         Count = Count + 1                        !      count indicates the next term
         Term = Term * (X / Count)                !      compute the value of next term
     END DO

     WRITE(*,*)      'After ', Count, ' iterations:'
     WRITE(*,*)      ' Exp(', X, ') = ', Sum
     WRITE(*,*)      ' From EXP()    = ', EXP(X)
     WRITE(*,*)      ' Abs(Error)    = ', ABS(Sum - EXP(X))

END PROGRAM Exponential
Click here to download this program.
PROGRAM INPUT AND OUTPUT
If the input value is 10.0, the following output shows that it requires 35 iterations to reach EXP(10.0)=22026.4648.
Comparing the result with the one obtained from Fortran intrinsic function EXP(), the absolute error is zero.

After 35 iterations:
  Exp(10.) = 22026.4648
  From EXP()   = 22026.4648
  Abs(Error)   = 0.E+0

If the input is -5.0, it takes 21 iterations to reach EXP(-5.0)=6.744734943E-3. The value from
using Fortran intrinsic function is 6.737946998E-3 and the absolute error is 6.787944585E-6.

After 21 iterations:
  Exp(-5.) = 6.744734943E-3
  From EXP()   = 6.737946998E-3
  Abs(Error)   = 6.787944585E-6


DISCUSSION

    
                                                                                                       i
        One obvious way of writing this program is computing each term directly using the formula x /i!.
                                                     i
        However, this is not a wise way, since both x and i! could get very large when x or i is large. One way to
        overcome this problem is rewriting the term as follows:




        Therefore, the (i+1)-th term is equal to the product of the i-th term and x/(i+1). In the
        program, variable Term is used to save the value of the current term and is updated with

        Term = Term * (X / Count)

        where Count is the value of i+1.

       Variable Sum is used to accumulate the values of terms.
       Since the tolerance value is usually small, the first term whose value is 1 cannot be less than the tolerance
        value. Therefore, the computation starts with the second term and 1 is saved to Sum.
       Count indicates which term is under consideration. Its plays the role of i in the infinite series shown
        above.
       Since the computation starts with the first term, the value of the first term, x, is saved to Term.
       For each iteration, the absolute value of Term is checked to see if it is less than the tolerance value
        Tolerance. If it is, the computation is done and EXIT.
       Otherwise, this term is added to Sum and prepare for the next term. Before this, Count is increased by
        one to point to the next term and consequently the next term is computed as Term * (X / Count).




COMPUTING THE GREATEST COMMON DIVISOR OF TWO POSITIVE INTEGERS
PROBLEM STATEMENT

The Greatest Common Divisor, GCD for short, of two positive integers can be computed with
Euclid's division algorithm. Let the given numbers be a and b, a >= b. Euclid's division
algorithm has the following steps:

    1.   Compute the remainder c of dividing a by b.
    2.   If the remainder c is zero, b is the greatest common divisor.
    3.   If c is not zero, replace a with b and b with the remainder c. Go back to step (1).

Write a program that reads in two integers and computes their greatest common divisor. Note that these two
input could be in any order.


SOLUTION
!   ---------------------------------------------------------
!   This program computes the GCD of two positive integers
!   using the Euclid method. Given a and b, a >= b, the
!   Euclid method goes as follows: (1) dividing a by b yields
!   a reminder c; (2) if c is zero, b is the GCD; (3) if c is
!   no zero, b becomes a and c becomes c and go back to
!   Step (1). This process will continue until c is zero.
!   ---------------------------------------------------------

PROGRAM GreatestCommonDivisor
   IMPLICIT NONE

    INTEGER        :: a, b, c

    WRITE(*,*) 'Two positive integers please --> '
    READ(*,*) a, b
    IF (a < b) THEN       ! since a >= b must be true, they
       c = a              ! are swapped if a < b
       a = b
       b = c
    END IF

    DO                                ! now we have a <= b
       c = MOD(a, b)                  !    compute c, the reminder
       IF (c == 0) EXIT               !    if c is zero, we are done.                    GCD = b
       a = b                          !    otherwise, b becomes a
       b = c                          !    and c becomes b
    END DO                            !    go back

    WRITE(*,*) 'The GCD is ', b

END PROGRAM GreatestCommonDivisor
Click here to download this program.




PROGRAM INPUT AND OUTPUT
      If the input values are 46332 and 71162, the computed GCD is 26.

         Two positive integers please -->
         46332 71162

         The GCD is 26

      If the input values are 128 and 32, the GCD is 32.

         Two positive integers please -->
         128 32

         The GCD is 32

      If the input values are 100 and 101, the GCD is 1 and 100 and 101 are relatively prime.

         Two positive integers please -->
         100 101

         The GCD is 1

      If the input values are 97 and 97, the GCD is of course 97.
          Two positive integers please -->
          97 97

         The GCD is 97


DISCUSSION

      Since there is no specific order for the two input values, it is possible that a may be less than b. In this
       case, these two values must be swapped.
      Thus, before entering the DO-loop, we are sure that a >= b holds.
      Then, the remainder is computed and stored to c. If c is zero, the program EXITs and displays the value of
       b as the GCD. The remainder is computed using Fortran intrinsic function MOD().
      If c is not zero, b becomes a and c becomes b, and reiterates.
      If we need to display the result as follows:
         The GCD of 46332 and 71162 is 26

       would the following change to the WRITE statement work?

       WRITE(*,*) 'The GCD of ', a, ' and ', b, ' is ', b



CHECKING IF A POSITIVE INTEGER IS A PRIME NUMBER

PROBLEM STATEMENT
An positive integer greater than or equal to 2 is a prime number if the only divisor of this integer
is 1 and itself.

Write a program that reads in an arbitrary integer and determines if it is a prime number.


SOLUTION
!   --------------------------------------------------------------------
!   Given an integer, this program determines if it is a prime number.
!   This program first makes sure the input is 2. In this case, it is
!   a prime number. Then, it checks to see the input is an even
!   number. If the input is odd, then this program divides the input
!   with 3, 5, 7, ....., until one of two conditions is met:
!      (1) if one these odd number evenly divides the input, the
!           input is not a prime number;
!      (2) if the divisor is greater than the square toot of the
!           input, the input is a prime.
!   --------------------------------------------------------------------

PROGRAM Prime
   IMPLICIT NONE

     INTEGER      :: Number                                   ! the input number
     INTEGER      :: Divisor                                  ! the running divisor

     READ(*,*) Number                      ! read in the input
     IF (Number < 2) THEN                  ! not a prime if < 2
        WRITE(*,*) 'Illegal input'
     ELSE IF (Number == 2) THEN            ! is a prime if = 2
        WRITE(*,*) Number, ' is a prime'
     ELSE IF (MOD(Number,2) == 0) THEN     ! not a prime if even
        WRITE(*,*) Number, ' is NOT a prime'
     ELSE                                  ! we have an odd number here
        Divisor = 3                        ! divisor starts with 3
        DO                                 ! divide the input number
            IF (Divisor*Divisor > Number .OR. MOD(Number, Divisor) == 0)                     EXIT
            Divisor = Divisor + 2          ! increase to next odd
        END DO
        IF (Divisor*Divisor > Number) THEN       ! which condition fails?
            WRITE(*,*) Number, ' is a prime'
        ELSE
            WRITE(*,*) Number, ' is NOT a prime'
        END IF
     END IF
END PROGRAM Prime
Click            here          to           download          this                           program.



PROGRAM INPUT AND OUTPUT

        If the input value is -1, the output is a message saying the input is not legal.

           Illegal input
      If the input is 2, it is a prime number.

         2 is a prime

      If the input is 3, it is also a prime number.

         3 is a prime

      If the input is 46, it is not a prime number since it is divisible by 2.

         46 is NOT a prime

      If the input is 97, it is a prime number.

         97 is a prime

      If the input is 9797, it is not a prime since it is divisible by 97.

         9797 is NOT a prime


DISCUSSION

      Since the input is an arbitrary integer, the program first makes sure its value is greater than or equal to 2;
       otherwise, a message is displayed.
      If the input is greater than or equal to 2, the program checks if it is actually equal to 2. If it is, just reports
       "2 is a prime".
      The next step is screening out all even numbers. Note that 2 has been checked before the control gets to
       the second ELSE-IF. If the input is divisible by 2, it is not a prime number.
      If the control can reach here, the input is an odd number greater than or equal to 3. Then, the program
       uses 3, 5, 7, 9, 11, ... these odd numbers as divisors to divide the input value stored in Number. These
       divisors are successively stored in Divisor.
      Of course, these divisors should start with 3; but, the question is when to stop. A naive answer would be
       "let us try up to Number-1" This is too slow since Number cannot be evenly divided by Number-1.

       A better choice is the square root of Number? Why is this strange value? If Number is
       divisible by a, then we can write Number=a*b for some b. If a is less than or equal to b,
       then a must be smaller than or equal to the square root of Number.

       Therefore, the upper limit of Divisor is the square root of Number. Stated in a slightly
       different way, it is "the square of Divisor is less than or equal to Number". This is better
       since it only uses integer arithmetic, while the one using square root involves REAL
       numbers.

      In the DO-loop, the value for Divisor starts with 3. As long as the square of Divisor is less than or equal to
       Number and Number is not divisible by Divisor, the iteration continues.

       Since Divisor can only be odd numbers, step-size is 2.
         This loop continues until one of the two conditions holds. If Divisor*Divisor > Number
         holds, then all odd numbers that are greater than or equal to 3 and less than or equal to the
         square root of Number have been tried and none of them can evenly divide Number.
         Therefore, Number is a prime number.

         If MOD(Number,Divisor) == 0 holds, Divisor divides Number and Number is not a
         prime.

        Let us take a look at a few examples:
              1. Let Number be 3. Divisor starts with 3. Since condition Divisor*Divisor > Number holds
                  immediately, 3 is a prime number.
              2. Let Number be 5. Divisor starts with 3. Since condition Divisor*Divisor > Number holds
                  immediately, 5 is a prime number.
              3. Let Number be 11. Divisor starts with 3. In the first iteration, both Divisor*Divisor > Number and
                  MOD(Number,Divisor) == 0 fail. So, Divisor is increased by 2, becoming 5. In the second
                  iteration, Divisor*Divisor > Number holds and 11 is a prime.
              4. Let Number be 91. Divisor starts with 3. In the first iteration, both Divisor*Divisor > Number and
                  MOD(Number,Divisor) == 0 fail. So, Divisor is increased by 2, becoming 5. In the second
                  iteration, both conditions still fail and Divisor is increased to 7. In the third iteration,
                  MOD(Number,Divisor) == 0 holds and 91 is not a prime.


NESTED DO-LOOPS


Just like an IF-THEN-ELSE-END IF can contain another IF-THEN-ELSE-END IF (see
nested IF for the details), a DO-loop can contain other DO-loops in its body. The body of the
contained DO-loop, usually referred to as the nested DO-loop, must be completely inside the
containing DO-loop. Note further that an EXIT statement only brings the control out of the
inner-most DO-loop that contains the EXIT statement.

Suppose we have the following nested DO loops:

DO
    statements-1
    DO
         statement-2
    END DO
    statement-3
END DO
Each iteration of the outer DO starts with statements-1. When the control reaches the inner DO, statements-2 is
executed until some condition of the inner DO brings the control out of it. Then, statements-3 is executed and this
completes one iteration. Any EXIT in the inner DO brings the control out of the inner DO to the first statement in
statement-3.

The following are a few simple examples:
   In the following nested loops, the outer one has i running from 1 to 9 with step size 1. For each iteration,
    say the i-th one, the inner loop iterates 9 times with values of j being 1, 2, 3, 4, 5, 6, 7, 8, 9. Therefore,
    with i fixed, the WRITE is executed 9 times and the output consists of i*1, i*2, i*3, ..., i*9.

      INTEGER :: i, j

      DO i = 1, 9
         DO j = 1, 9
           WRITE(*,*)           i*j
         END DO
      END DO

    Once this is done, the value of i is advanced to the next one, and the inner loop will iterate 9 times
    again displaying the product of the new i and 1, 2, 3,4 ..., 9.

    The net effect is a multiplication table. For i=1, the value if 1*1, 1*2, 1*3, ..., 1*9 are
    displayed; for i=2, the displayed values are 2*1, 2*2, 2*3, ..., 2*9; ...; for i=9, the
    displayed values are 9*1, 9*2, 9*3, ..., 9*9.

   The following shows a nested DO-loop. The outer one lets u run from 2 to 5. For each u, the inner DO
    lets v runs from 1 to u-1. Therefore, when u is 2, the values for v is from 1 to 1. When u is 3, the values
    for v are 1 and 2. When u is 4, the values for v are 1, 2, and 3. Finally, when u is 5, the values for v are 1,
    2, 3 and 4.

      INTEGER :: u, v
      INTEGER :: a, b, c

      DO u = 2, 5
         DO v = 1, u-1
             a = 2*u*v
             b = u*u - v*v
             c = u*u + v*v
             WRITE(*,*) a, b, c
         END DO
      END DO

    The above discussion can be summarized in the following table:


                                               u Values for v

                                               2 1

                                               3 1 2

                                               4 1 2 3

                                               5 1 2 3 4
    For each pair of u and v, the inner loop computes a, b and c. Thus, it will generate
    the following result (please verify it):

                                              u v a b c

                                              2 1 4 3 5

                                                  1 6 8 10
                                              3
                                                  2 12 5 13

                                                  1 8 15 17

                                              4 2 16 12 20

                                                  3 24 7 25

                                                  1 10 24 26

                                                  2 20 21 29
                                              5
                                                  3 30 16 34

                                                  4 40 9 41



   It is obvious that the inner DO-loop computes the sum of all integers in the range of 1 and i (i.e., Sum is
    equal to 1+2+3+...+i). Since i runs from 1 to 10, the following loop computes ten sums: 1, 1+2, 1+2+3,
    1+2+3+4, ...., 1+2+3+...+9, and 1+2+3+...+9+10.

      INTEGER :: i, j, Sum

      DO i = 1, 10
         Sum = 0
         DO j = 1, i
             Sum = Sum + j
         END DO
         WRITE(*,*) Sum
      END DO

   The program below uses Newton's method for computing the square root of a positive number. In fact,
    it computes the square roots of the numbers 0.1, 0.1, ..., 0.9 and 1.0.

    REAL :: Start = 0.1, End = 1.0, Step = 0.1
    REAL :: X, NewX, Value

    Value = Start
    DO
           IF (Value > End) EXIT
           X = Value
           DO
               NewX = 0.5*(X + Value/X)
               IF (ABS(X - NewX) < 0.00001) EXIT
               X = NewX
           EBD DO
           WRITE(*,*) 'The square root of ', Value, ' is ', NewX
           Value = Value + Step
        END DO

        Newton's method is taken directly from the programming example, where X is the current guess, NewX
        is the new guess, and Value is the number for square root computation. The EXIT statement brings the
        execution of the inner DO to the WRITE statement.

        If the inner loop is removed, we have the outer loop as follows:

        REAL :: Start = 0.1, End = 1.0, Step = 0.1
        REAL :: X, NewX, Value

        Value = Start
        DO
           IF (Value > End) EXIT
        !
        ! the inner loop computes the result in NewX
        !
           WRITE(*,*) 'The square root of ', Value, ' is ', NewX
           Value = Value + Step
        END DO

        It is clear that the value of Value starts with 0.1 and have a step size 0.1 until 1.0. Thus, the values of
        Value are 0.1, 0.2, 0.3, ..., 0.9 and 1.0. For each value of Value, the inner loop computes the square root
        of Value. The EXIT statement in the outer loop brings the control out of the outer loop.


COMPUTING CLASSES AVERAGES

PROBLEM STATEMENT

There are four sessions of CS110 and CS201, each of which has a different number of students.
Suppose all students take three exams. Someone has prepared a file that records the exam scores
of all students. This file has a form as follows:

4
3
97.0    87.0    90.0
100.0   78.0    89.0
65.0    70.0    76.0
2
100.0   100.0 98.0
97.0    85.0 80.0
4
78.0 75.0 90.0
89.0 85.0 90.0
100.0 97.0 98.0
56.0 76.0 65.0
3
60.0 65.0 50.0
100.0 99.0 96.0
87.0 74.0 81.0
The first number 4 gives the number of classes in this file. For each class, it starts with an integer, giving the
number of students in that class. Thus, the first class has 3 students, the second has 2, the third has 4 and the
fourth has 3. Following the number of students, there are that number of lines each of which contains the three
scores of a student.

Write a program that reads in a file of this form and computes the following information:

     1.   the average of each student;
     2.   the class average of each exam; and
     3.   the grant average of the class.

Click here to download this data file.


SOLUTION
!   ----------------------------------------------------------
!   This program computes the average of each student and the
!   the average of the class. The input file starts with an
!   integer giving the number of classes. For each class, the
!   input starts with an integer giving the number of students
!   of that class, followed that number of lines on each of
!   which there are three scores. This program reads in the
!   scores and computes their average and also the class
!   averages of each score and the grant average of the class.
!   ----------------------------------------------------------

PROGRAM ClassAverage
   IMPLICIT NONE

     INTEGER     ::   NoClass              ! the no. of classes
     INTEGER     ::   NoStudent            ! the no. of students in each class
     INTEGER     ::   Class, Student       ! DO control variables
     REAL        ::   Score1, Score2, Score3, Average
     REAL        ::   Average1, Average2, Average3, GrantAverage

     READ(*,*) NoClass               ! read in the # of classes
     DO Class = 1, NoClass           ! for each class, do the following
        READ(*,*) NoStudent          !   the # of student in this class
        WRITE(*,*)
        WRITE(*,*) 'Class ', Class, ' has ', NoStudent, ' students'
        WRITE(*,*)
        Average1 = 0.0               !   initialize average variables
        Average2 = 0.0
        Average3 = 0.0
        DO Student = 1, NoStudent    !   for each student in this class
           READ(*,*) Score1, Score2, Score3    ! read in his/her scores
           Average1 = Average1 + Score1       ! prepare for class average
           Average2 = Average2 + Score2
           Average3 = Average3 + Score3
           Average = (Score1 + Score2 + Score3) / 3.0   ! average of this one
           WRITE(*,*) Student, Score1, Score2, Score3, Average
       END DO
       WRITE(*,*) '----------------------'
       Average1      = Average1 / NoStudent   ! class average of score1
       Average2      = Average2 / NoStudent   ! class average of score2
       Average3      = Average3 / NoStudent   ! class average of score3
       GrantAverage = (Average1 + Average2 + Average3) / 3.0
       WRITE(*,*) 'Class Average: ', Average1, Average2, Average3
       WRITE(*,*) 'Grant Average: ', GrantAverage
    END DO

END PROGRAM ClassAverage
Click here to download this program.




PROGRAM INPUT AND OUTPUT
The input shown above should produce the following output:

Class 1 has 3 students

1, 97., 87., 90., 91.3333359
2, 100., 78., 89., 89.
3, 65., 70., 76., 70.3333359
----------------------
Class Average: 87.3333359, 78.3333359,                   85.
Grant Average: 83.5555573

Class 2 has 2 students

1, 100., 100., 98., 99.3333359
2, 97., 85., 80., 87.3333359
----------------------
Class Average: 98.5, 92.5, 89.
Grant Average: 93.3333359

Class 3 has 4 students

1, 78., 75., 90., 81.
2, 89., 85., 90., 88.
3, 100., 97., 98., 98.3333359
4, 56., 76., 65., 65.6666641
----------------------
Class Average: 80.75, 83.25, 85.75
Grant Average: 83.25

Class 4 has 3 students

1, 60., 65., 50., 58.3333321
2, 100., 99., 96., 98.3333359
3, 87., 74., 81., 80.6666641
----------------------
Class Average: 82.3333359,                 79.3333359,         75.6666641
Grant Average: 79.1111145


DISCUSSION
This is a relatively easy problem. Here is an analysis in case you need it.

Since for each class we need to compute the average of each student, the class average of each
exam, and the grant average of the whole class, we might immediately come up the following
scheme:

READ(*,*) NoClass
DO Class = 1, NoClass
    compute various average for this class
    display exam averages and class the grant average
END DO
Thus, "compute various average for the class" becomes the job of the inner loop. This loop should read in the
scores of each student and do some computation as follows:

READ(*,*) NoStudent
DO Student = 1, NoStudent
    READ(*,*) Score1, Score2, Score3
    compute the average of this student
    compute the exam averages
END DO
Now, the only trouble is how to compute the exam averages. In fact, this inner loop has no way to compute the
exam averages directly; but, it could compute the sum of the scores of a particular exam. After this inner loop
ends, the outer loop could divide the sum with the number of students to obtain the average. To accumulate these
sums, we need to initialize variables. Thus, the result is:

Average1 = 0.0
Average2 = 0.0
Average3 = 0.0
DO Student = 1, NoStudent
     READ(*,*) Score1, Score2, Score3
     Average1 = Average1 + Score1
     Average2 = Average2 + Score2
     Average3 = Average3 + Score3
     Average = (Score1 + Score2 + Score3) / 3.0
     WRITE(*,*) Student, Score1, Score2, Score3, Average
END DO
WRITE(*,*) '----------------------'
Average1           = Average1 / NoStudent
Average2           = Average2 / NoStudent
Average3           = Average3 / NoStudent
GrantAverage = (Average1 + Average2 + Average3) / 3.0
In the above, Average1, Average2 and Average3 are for the exam averages. They must be initialized right before
entering the inner DO-loop, since the exam averages are computed for each class. The actual average is computed
right after the inner DO-loop by dividing Average1, Average2 and Average3 with the number of students
NoStudents. Once we have the exam averages, the grant average is computed as the average of these exam
averages.
COMPUTING A SET OF VALUES OF EXP(X)

PROBLEM STATEMENT

In a previous example we have discussed the way of using infinite series for computing the
exponential function EXP(x). The exponential function, EXP(x), is usually defined to be the
sum of the following infinite series:




Write a program that reads in an initial value Begin, a final value End and a step size Step, and
computes the exponential function value at Begin, Begin+Step, Begin+2*Step, ...


SOLUTION
!   --------------------------------------------------------------
!   This program computes exp(x) for a range of x. The range
!   is in the form of beginning value, final value and step size.
!   For each value in this range, the infinite series of exp(x)
!   is used to compute exp(x) up to a tolerance of 0.00001.
!   This program display the value of x, the exp(x) from infinite
!   series, the exp(x) from Fortran's intrinsic function exp(x),
!   the absolute error, and the relative error.
!   --------------------------------------------------------------

PROGRAM Exponential
   IMPLICIT NONE

     INTEGER            ::   Count             !      term count
     REAL               ::   Term              !      a term
     REAL               ::   Sum               !      the sum of series
     REAL               ::   X                 !      running value
     REAL               ::   ExpX              !      EXP(X)
     REAL               ::   Begin, End, Step !       control values
     REAL, PARAMETER    ::   Tolerance = 0.00001         ! tolerance

     WRITE(*,*)    'Initial, Final and Step please --> '
     READ(*,*)     Begin, End, Step

     X = Begin                                    ! X starts with the beginning value
     DO
        IF (X >    End) EXIT                      !   if X is > the final value, EXIT
        Count =    1                              !   the first term is 1 and counted
        Sum    =   1.0                            !   thus, the sum starts with 1
        Term =     X                              !   the second term is x
        ExpX =     EXP(X)                         !   the exp(x) from Fortran's EXP()
        DO                                        !   for each term
            IF (ABS(Term) < Tolerance)                  EXIT ! if too small, exit
            Sum   = Sum + Term                             !   otherwise, add to sum
            Count = Count + 1                              !   count indicates the next term
            Term = Term * (X / Count)                      !   compute the value of next term
         END DO

         WRITE(*,*)        X, Sum, ExpX, ABS(Sum-ExpX), ABS((Sum-ExpX)/ExpX)

        X = X + Step
     END DO

END PROGRAM Exponential
Click here to download this program.




PROGRAM INPUT AND OUTPUT
If the input for Begin, End and Step are -1.0, 1.0 and 0.1, the program would generate the following output.

    Initial, Final and Step please -->
    -1., 0.367881894, 0.36787945, 2.443790436E-6, 6.642911103E-6
    -0.899999976, 0.406570643, 0.40656966, 9.834766388E-7, 2.41896214E-6
    -0.799999952, 0.449325144, 0.449328989, 3.844499588E-6, 8.556090506E-6
    -0.699999928, 0.496584028, 0.496585339, 1.311302185E-6, 2.640638058E-6
    -0.599999905, 0.5488168, 0.548811674, 5.125999451E-6, 9.340179531E-6
    -0.499999911, 0.606532216, 0.606530726, 1.490116119E-6, 2.456785978E-6
    -0.399999917, 0.670314729, 0.670320094, 5.36441803E-6, 8.002770301E-6
    -0.299999923, 0.740817249, 0.740818262, 1.013278961E-6, 1.367783398E-6
    -0.199999928, 0.818733335, 0.818730831, 2.503395081E-6, 3.05765343E-6
    -9.999992698E-2, 0.904833436, 0.904837489, 4.053115845E-6, 4.479385552E-
6
  7.450580597E-8, 1., 1.00000012, 1.192092896E-7, 1.192092753E-7
  0.100000076, 1.10516667, 1.10517097, 4.291534424E-6, 3.883140835E-6
  0.200000077, 1.22140002, 1.22140288, 2.861022949E-6, 2.342407242E-6
  0.300000072, 1.34985793, 1.34985888, 9.536743164E-7, 7.064992928E-7
  0.400000066, 1.4918189, 1.49182475, 5.841255188E-6, 3.915510206E-6
  0.50000006, 1.64871967, 1.64872134, 1.668930054E-6, 1.012257258E-6
  0.600000083, 1.82211316, 1.822119, 5.841255188E-6, 3.205748499E-6
  0.700000107, 2.01375127, 2.01375294, 1.668930054E-6, 8.287660194E-7
  0.800000131, 2.22553682, 2.22554111, 4.291534424E-6, 1.928310667E-6
  0.900000155, 2.45960236, 2.45960355, 1.192092896E-6, 4.846687034E-7
The first column shows the data values (i.e., -1.0, -0.9, ..., 1.0), the second is the values from using infinite series
with a tolerance value 0.00001, the third column contains the values from Fortran's intrinsic function EXP(), the
forth column has the absolute errors, and the fifth column has the relative errors.

Let S be the sum computed using infinite series and exp(x) be the result from Fortran's intrinsic
function. Then, the absolute error and relative error are defined as follows:
You may find out that the value for X are not -1.0, -0.9, -0.8, ..., 0.0, 0.1, 0.2, ..., 0.9 and 1.0. It
contains errors. For example, the last value should be 1.0 instead of 0.900000155. This is a
problem of precision being not high enough. See the KIND attribute in a later chapter.


DISCUSSION

        For the computation using infinite series, see a previous example for the details.
        Since the data points are Begin, Begin+Step, Begin+2*Step and so on, it is simply a DO-loop as follows:

           X = Begin
           DO
              IF (X > End) EXIT
                ... compute EXP(X) here ...
              X = X + Step
           END DO

        Inserting the computation part into the place "... computing EXP(X) here ..." gives the program shown
         above.




ARMSTRONG NUMBERS

PROBLEM STATEMENT

An Armstrong number of three digits is an integer such that the sum of the cubes of its digits is
equal to the number itself. For example, 371 is an Armstrong number since 3**3 + 7**3 + 1**3
= 371.

Write a program to find all Armstrong number in the range of 0 and 999.


SOLUTION
!   ---------------------------------------------------------------
!   This program computes all Armstrong numbers in the range of
!   0 and 999. An Armstrong number is a number such that the sum
!   of its digits raised to the third power is equal to the number
!   itself. For example, 371 is an Armstrong number, since
!   3**3 + 7**3 + 1**3 = 371.
!   ---------------------------------------------------------------

PROGRAM ArmstrongNumber
   IMPLICIT NONE

     INTEGER :: a, b, c                                    ! the three digits
     INTEGER :: abc, a3b3c3                                ! the number and its cubic sum
     INTEGER :: Count                                      ! a counter
    Count = 0
    DO a = 0, 9                           ! for the left most digit
       DO b = 0, 9                        !   for the middle digit
           DO c = 0, 9                    !     for the right most digit
              abc     = a*100 + b*10 + c  !        the number
              a3b3c3 = a**3 + b**3 + c**3 !        the sum of cubes
              IF (abc == a3b3c3) THEN     !        if they are equal
                  Count = Count + 1       !           count and display it
                  WRITE(*,*) 'Armstrong number ', Count, ': ', abc
              END IF
           END DO
       END DO
    END DO

END PROGRAM        ArmstrongNumber
Click               here           to                         download                    this                  program.



PROGRAM INPUT AND OUTPUT
The following is the output from the above program. Thus, there are six Armstrong numbers in the range of 0 and
999.

Armstrong     number     1:   0
Armstrong     number     2:   1
Armstrong     number     3:   153
Armstrong     number     4:   370
Armstrong     number     5:   371
Armstrong     number     6:   407


DISCUSSION

       Three-digit numbers are 000, 001, 002, ..., 009, 010, 011, ..., 019, 020, 021, 022, ..., 099, 100, 101, 102, ...,
        109, 110, ... 990, 991, ..., 999. As you can see the right-most digits changes faster than the middle one,
        which in turn is faster than the left-most one. As the left-most and the middle digits are fixed to 0 and 0,
        the right-most digit changes from 0 to 9. Then, the middle one is increased from 0 to 1. In other words,
        whenever the right-most digit completes a 0 to 9 cycle, the middle digit is increased by one and the right-
        most digit restart another 0 to 9 cycle. By the same token, whenever the middle digit completes a 0 to 9
        cycle, the left-most digit is increased by 1 and the middle digit restarts another 0 to 9 cycle.

        Therefore, if a, b and c are the left-most, the middle and the right-most digits, the above
        discussion is formalized with the following three nested DO-loops:

        DO a = 0, 9
           DO b = 0, 9
               DO c = 0, 9
                  ... the number is abc .....
               END DO
           END DO
        END DO
        Now, in the inner most DO, the number in hand is abc, where a, b and c are the left-most, middle and the
         right-most digits. The number itself is of course a*100 + b*10 + c. The sum of the cubes of the digits is
         a**3 + b**3 + c**3. In the program, these two are stored in abc and a3b3c3, respectively.
        Finally, if abc and a3b3c3 are equal, we have found an Armstrong number. We can use abc or a3b3c3




FINDING ALL PRIME NUMBERS IN THE RANGE OF 2 AND N

PROBLEM STATEMENT

In a previous example, we have discussed how to determine if a positive integer is a prime
number. In this one, we shall find all prime numbers in the range of 2 and N, where N is an input
integer.

Write a program to read a value of N, make sure that the value of N is greater than or equal to 2,
and display all prime numbers in the range of 2 and N. In case the value of N is less than 2, your
program should keep asking the user to try again until a value that is greater than or equal to 2 is
read.


SOLUTION
!   ---------------------------------------------------------------
!   This program finds all prime numbers in the range of 2 and an
!   input integer.
!   ---------------------------------------------------------------

PROGRAM Primes
   IMPLICIT NONE

     INTEGER     :: Range, Number, Divisor, Count

     WRITE(*,*) 'What is the range ? '
     DO                                                    ! keep trying to read a good input
        READ(*,*) Range                                    ! ask for an input integer
        IF (Range >= 2) EXIT                               ! if it is GOOD, exit
        WRITE(*,*) 'The range value must                   be >= 2. Your input = ', Range
        WRITE(*,*) 'Please try again:'                     ! otherwise, bug the user
     END DO

     Count = 1                           ! input is correct. start counting
     WRITE(*,*)                          ! since 2 is a prime
     WRITE(*,*) 'Prime number #', Count, ': ', 2
     DO Number = 3, Range, 2             ! try all odd numbers 3, 5, 7, ...

         Divisor = 3                       ! divisor starts with 3
         DO
            IF (Divisor*Divisor > Number .OR. MOD(Number,Divisor) == 0)                                EXIT
           Divisor = Divisor + 2                           ! if does not evenly divide, next odd
        END DO

       IF (Divisor*Divisor > Number) THEN      ! are all divisor exhausted?
           Count = Count + 1              ! yes, this Number is a prime
           WRITE(*,*) 'Prime number #', Count, ': ', Number
       END IF
    END DO

    WRITE(*,*)
    WRITE(*,*)       'There are ', Count, ' primes in the range of 2 and ', Range

END PROGRAM       Primes

Click here to download this program.




PROGRAM INPUT AND OUTPUT

       The following shows an interaction between the user and program. First, the users type in -10, which is
        less than 2. This program displays the input value and a message asking the user to try again. The user
        then types in 0, which is still less than 2, causing the same message to occur. The users types in 1 and the
        same message appears. Finally, after the user types in 5, the program reports that there are three prime
        numbers in the range of 2 and 5, namely: 2, 3, and 5.

          What is the range ?
          -10
          The range value must be >= 2.                  Your input = -10
          Please try again:
          0
          The range value must be >= 2.                  Your input = 0
          Please try again:
          1
          The range value must be >= 2.                  Your input = 1
          Please try again:
          5

          Prime number #1: 2
          Prime number #2: 3
          Prime number #3: 5

          There are 3 primes in the range of 2 and 5

       The following is generated with input 100. There are 25 prime numbers in the range of 2 and 100.

          What is the range ?
          100

          Prime    number     #1:   2
          Prime    number     #2:   3
          Prime    number     #3:   5
          Prime    number     #4:   7
          Prime    number     #5:   11
         Prime    number    #6: 13
         Prime    number    #7: 17
         Prime    number    #8: 19
         Prime    number    #9: 23
         Prime    number    #10: 29
         Prime    number    #11: 31
         Prime    number    #12: 37
         Prime    number    #13: 41
         Prime    number    #14: 43
         Prime    number    #15: 47
         Prime    number    #16: 53
         Prime    number    #17: 59
         Prime    number    #18: 61
         Prime    number    #19: 67
         Prime    number    #20: 71
         Prime    number    #21: 73
         Prime    number    #22: 79
         Prime    number    #23: 83
         Prime    number    #24: 89
         Prime    number    #25: 97

         There are 25 primes in the range of 2 and 100


DISCUSSION

      We shall use part of the program shown in a previous example for checking if an integer is a prime
       number. Please refer to that example for the details.
      How do we write a bullet-proof program so that the values for N and Range in the program are always
       correct? Here is the way our program uses:

         WRITE(*,*) 'What is the range ? '
         DO
            READ(*,*) Range
            IF (Range >= 2) EXIT
              ... incorrect input here ...
         END DO

       It first asks for a number. The actual READ is in the DO-loop. After reading in a value for Range, this value
       is checked to see if it is greater than or equal to 2. If it is, EXIT and find prime numbers, since we have
       read in a good input. Otherwise, the input is incorrect and the program shows a message and loops back
       to read a new one.

      After reading in a correct value for Range, we can start prime number searching. Since Range is larger
       than or equal to 2, 2 must be included since it is a prime number.
      All the other prime numbers are odd numbers. As a result, we only try to determine if a number in the list
       of 3, 5, 7, 9, 11, ...., up to Range, is a prime number. This is, of course, the job of a DO-loop:

         DO Number = 3, Range, 2
            ... determine if Number is a prime number ...
            ... if Number is a prime number, display it ...
         END DO
        The segment in the previous example can be used to replace "...determine if Number is a prime
         number..." and the final program is the one shown above.


FINDING ALL PRIME FACTORS OF A POSITIVE INTEGER

PROBLEM STATEMENT

As we have learned in high school, any positive integer can be factorized into prime factors. For
example, 586390350 can be factorized as follows:




Thus, 586390350 has factors 2, 3, 5, 5,, 7, 7, 13, 17, 19 and 19. Note that all factors are prime
numbers.

Write a program that reads in an integer greater than or equal to 2 and finds all of its prime
factors.

This problem is a little more difficult than the others and may require longer time to
understand its logic.


SOLUTION
!   ---------------------------------------------------------------
!   This program determines all prime factors of an n integer >= 2.
!   It first removes all factors of 2. Then, removes all factors
!   of 3, 5, 7, and so on. All factors must be prime numbers since
!   when a factor is tried all of whose non-prime factors have
!   already been removed.
!   ---------------------------------------------------------------

PROGRAM Factorize
   IMPLICIT NONE

     INTEGER     :: Input
     INTEGER     :: Divisor
     INTEGER     :: Count

     WRITE(*,*)      'This program factorizes any integer >= 2 --> '
     READ(*,*)       Input

     Count = 0
     DO                         ! here, we try to remove all factors of 2
        IF (MOD(Input,2) /= 0 .OR. Input == 1) EXIT
        Count = Count + 1       ! increase count
        WRITE(*,*) 'Factor # ', Count, ': ', 2
        Input = Input / 2       ! remove this factor from Input
     END DO
    Divisor = 3                 ! now we only worry about odd factors
    DO                          ! 3, 5, 7, .... will be tried
       IF (Divisor > Input) EXIT     ! if a factor is too large, exit and done
       DO                       ! try this factor repeatedly
           IF (MOD(Input,Divisor) /= 0 .OR. Input == 1) EXIT
           Count = Count + 1
           WRITE(*,*) 'Factor # ', Count, ': ', Divisor
           Input = Input / Divisor   ! remove this factor from Input
       END DO
       Divisor = Divisor + 2    ! move to next odd number
    END DO

END PROGRAM Factorize
Click here to download this program.




PROGRAM INPUT AND OUTPUT

       If the input is 100, the output consists of four factors 2, 2, 5 and 5.

          This program factorizes any integer >= 2 -->
          100

          Factor     #   1:   2
          Factor     #   2:   2
          Factor     #   3:   5
          Factor     #   4:   5

       If the input is 16, the output consists of four factors 2, 2, 2 and 2.

          This program factorizes any integer >= 2 -->
          16

          Factor     #   1:   2
          Factor     #   2:   2
          Factor     #   3:   2
          Factor     #   4:   2

       If the input is 53, since it is a prime number, the output has only one factor: 53 itself.

          This program factorizes any integer >= 2 -->
          53

          Factor # 1: 53

       If the input value is 586390350, the output consists of 10 factors 2, 3, 5, 5, 7, 7, 13, 17, 19 and 19.

          This program factorizes any integer >= 2 -->
          586390350

          Factor # 1: 2
          Factor # 2: 3
         Factor    #   3: 5
         Factor    #   4: 5
         Factor    #   5: 7
         Factor    #   6: 7
         Factor    #   7: 13
         Factor    #   8: 17
         Factor    #   9: 19
         Factor    #   10: 19


DISCUSSION

      How to remove a factor from a given number? I believe you have learned it in high school. Let the given
       number be n and we know x is a factor of n. Then, we just keep dividing n by x until the quotient is 1 or x
       cannot evenly divide n.

       For example, 3 is a factor of 72. The first division yields a quotient 24=72/3. The second
       division yields a quotient 8=24/3. Thus, the original number 72 has two factors of 3.

       If n and x are both 53, then the first division yields a quotient 1=53/53. Since the quotient
       is 1, no more division is necessary and 53 has a factor 53!

      So, how to convert the above idea to a program? Let us use Input and Divisor for n and x, respectively.
       The following DO-loop will do the job:

         DO
            IF (MOD(Input,Divisor) /= 0 .OR. Input == 1) EXIT
            ... since MOD(Input,Divisor)=0 here, Divisor is a factor...
            Input = Input / Divisor
         END DO

       In the above, if Divisor cannot evenly divide Input or Input is 1, we exit the loop. The former condition
       states that Divisor is not a factor of Input, while the latter means Input is 1 and does not have any other
       factor.

       If both conditions are .FALSE., then Divisor can evenly divide Input and Input is not 1.
       Therefore, Input is a factor of Divisor. To remove it, just perform a division and this is
       the meaning of Input = Input / Divisor.

      Since 2 is the only even prime number, we'd better remove all factors of 2 before starting any other work.
       Therefore, letting Divisor to 2 in the above code will remove all factor of 2:

          DO
             IF (MOD(Input,2) /= 0 .OR. Input == 1) EXIT
             ... since MOD(Input,2)=0 here, 2 is a factor...
             Input = Input / Divisor
          END DO

       After exiting this loop, we are sure the new value of Input will have no factors of 2. Then, we can try all
       odd numbers to see some of them could be factors.
      To try odd numbers, it is simply the following:

      Divisor = 3
      DO
         IF (Divisor > Input) EXIT
         ...remove all factors of Divisor...
         Divisor = Divisor + 2
      END DO

     Putting everything together, it is the program shown above.
     Why the factors found are prime numbers? A good question, indeed.

      It is not difficult to answer, however. If Input does have a composite factor (a composite
      number is the product of several prime numbers), say x = a*b, where a is a prime
      number. Then, before the program can test if x is a factor, a has been tested since a < x,
      and the factor a is removed. Consequently, only a possible factor b remains. In other
      words, composite number x is never tested and the program will not report any composite
      factors.

     Let us factorize 586390350 as an example:
           1. Factors of 2 are removed first. Removing the first factor of 2 yields 293195175=586390350/2.
           2. Since 293195175 is not even, it has no more factors of 2. So, we shall try all odd numbers: 3, 5, 7,
               9, 11, ...
           3. Removing a factor of 3 yields 97731725=293195175/3.
           4. Since 97731725 has no factors of 3, try 5.
           5. Removing a factor of 5 yields 19546345=97731725/5.
           6. Removing a factor of 5 a second time yields 3909269=19546345/5.
           7. Since 3909269 has no factors of 5, try 7.
           8. Removing a factor of 7 yields 558467=3909269/7.
           9. Removing a second factor of 7 yields 79781=558467/7.
           10. Since 79781 has no factors of 7, try 9.
           11. Since 79781 has no factors of 9, try 11.
           12. Since 79781 has no factors of 11, try 13.
           13. Removing a factor of 13 yields 6137=79781/13.
           14. Since 6137 has no factor of 13, try 15.
           15. Since 6137 has no factor of 15, try 17.
           16. Removing a factor of 17 yields 361=6137/17.
           17. Since 361 has no factor of 17, try 19.
           18. Removing a factor of 19 yields 19=361/19.
           19. Removing a second factor of 19 yields 1=19/19.
           20. Since the quotient is already 1, stop and all factors have been reported.

      You might feel this is not a very efficient method since testing if 9 and 15 are factors are
      redundant. Yes, you are right; but, this is already a reasonable complicated program for
      CS110 and CS201. You could learn more efficient factorization algorithms in other
      computer science and/or mathematics courses, since this is an extremely important topic.




HANDLING END-OF-FILE: THE READ STATEMENT REVISITED
In many situations, you really do not know the number of items in the input. It could be so large
to be counted accurately. Consequently, we need a method to handle this type of input. In fact,
you have encountered such a technique in Programming Assignment 1 in which a keyword
IOSTAT= was used in a READ statement. The following is its syntax:

INTEGER :: IOstatus

READ(*,*,IOSTAT=IOstatus) var1, var2, ..., varn
The third component of the above READ is IOSTAT= followed by an INTEGER variable. The meaning of this new
form of READ is simple:

After executing the above READ statement, the Fortran compiler will put an integer value into
the integer variable following IOSTAT=, IOstatus above. Based on the value of IOstatus, we
have three different situations:

    1.   If the value of IOstatus is zero, the previous READ was executed flawlessly and all variables have received
         their input values. This is the normal case.
    2.   If the value of IOstatus is positive, the previous READ has encountered some problem. In general, without
         knowing the system dependent information, it is impossible to determine what the problem was.
         However, if hardware and I/O devices are working, a commonly seen problem would be illegal data. For
         example, supplying a real number to an integer variable. If IOstatus is positive, you cannot trust the
         values of the variables in the READ statement; they could all contain garbage values, or some of them are
         fine while the others are garbage.
    3.   If the value of IOstatus is negative, it means the end of the input has reached. Under this circumstance,
         some or all of the variables in the READ may not receive input values.

What is the end of file? How do we generate it? If you prepare your input using a file, when
you save it, the system will generate a special mark, called end-of-file mark, at the end of that
file. Therefore, when you read the file and encounter that special end-of-file mark, the system
would know there is no input data after this mark. If you try to read passing this mark, it is
considered as an error.

If you prepare the input using keyboard, hiting the Ctrl-D key would generate the end-of-mark
under UNIX. Once you hit Ctrl-D, the system would consider your input stop at there. If your
program tries to read passing this point, this is an error.

However, with IOSTAT=, you can catch this end-of-file mark and do something about it. A
commonly seen application is that let the program to count the number of data items as will be
shown in examples below.


EXAMPLES

        In the following code, the DO-loop keeps reading in three integer values into variables a, b and c. After
         executing a READ, if Reason is greater than zero, something was wrong in the input; if Reason is less than
         zero, end-of-file has reached. Only if Reason is zero, one can start normal processing.
        INTEGER :: Reason
        INTEGER :: a, b, c


        DO
           READ(*,*,IOSTAT=Reason) a, b, c
           IF (Reason > 0) THEN
               ... something wrong ...
           ELSE IF (Reason < 0) THEN
               ... end of file reached ...
           ELSE
               ... do normal stuff ...
           END IF
        END DO

   The following code keeps reading an integer at a time and adds them to a variable sum. If io is greater
    than zero, it displays 'Check input. Something was wrong'; if io is less than zero, it displays the value of
    sum. Note that both cases EXIT the DO-loop since continuing the loop execution makes no sense.
    Otherwise, the value of x is meaningful and is added to sum.

        INTEGER :: io, x, sum

        sum = 0
        DO
           READ(*,*,IOSTAT=io) x
           IF (io > 0) THEN
               WRITE(*,*) 'Check input. Something was wrong'
               EXIT
           ELSE IF (io < 0) THEN
               WRITE(*,*) 'The total is ', sum
               EXIT
           ELSE
               sum = sum + x
           END IF
        END DO

    Now if the input is

    1
    3
    4

    the above code should display 8 (=1+3+4). If the input is

    1
    @
    3

    since @ is not a legal integer, the second time the READ is executed, io would receive a positive number
    and the above program exits the DO-loop.
COMPUTING ARITHMETIC, GEOMETRIC AND HARMONIC MEANS: REVISITED

PROBLEM STATEMENT

The arithmetic mean (i.e., average), geometric mean and harmonic mean of a set of n numbers
x1, x2, ..., xn is defined as follows:




Since computing geometric mean requires taking root, it is further required that all input data
values must be positive. As a result, this program must be able to ignore those non-positive
items. However, this may cause all input items ignored. Therefore, before computing the means,
this program should have one more check to see if there are valid items.

Unlike a previous example, this program does not know the number of input items and must
handle incorrect input data and ignore them.


SOLUTION
!   -----------------------------------------------------------
!   This program can read an unknown number of input until the
!   end of file is reached. It calculates the arithmetic,
!   geometric, and harmonic means of these numbers.
!
!   This program uses IOSTAT= to detect the following two
!   conditions:
!      (1) if the input contains illegal symbols (not numbers)
!      (2) if the end of input has reached
!   -----------------------------------------------------------

PROGRAM   ComputingMeans
   IMPLICIT NONE

     REAL      ::   X
     REAL      ::   Sum, Product, InverseSum
     REAL      ::   Arithmetic, Geometric, Harmonic
     INTEGER   ::   Count, TotalValid
     INTEGER   ::   IO                        ! this is new variable

     Sum            =   0.0
     Product        =   1.0
     InverseSum     =   0.0
     TotalValid     =   0
     Count          =   0
    DO
       READ(*,*,IOSTAT=IO) X              ! read in data
       IF (IO < 0) EXIT                   ! IO < 0 means end-of-file reached
       Count = Count + 1                  ! otherwise, there are data in input
       IF (IO > 0) THEN                   ! IO > 0 means something wrong
           WRITE(*,*) 'ERROR: something wrong in your input'
           WRITE(*,*) 'Try again please'
       ELSE                               ! IO = 0 means everything is normal
           WRITE(*,*) 'Input item ', Count, ' --> ', X
           IF (X <= 0.0) THEN
              WRITE(*,*) 'Input <= 0. Ignored'
           ELSE
              TotalValid = TotalValid + 1
              Sum        = Sum + X
              Product    = Product * X
              InverseSum = InverseSum + 1.0/X
           END IF
       END IF
    END DO

    WRITE(*,*)
    IF (TotalValid > 0) THEN
       Arithmetic = Sum / TotalValid
       Geometric = Product**(1.0/TotalValid)
       Harmonic   = TotalValid / InverseSum

       WRITE(*,*)           '# of items read -->            ',   Count
       WRITE(*,*)           '# of valid items ->            ',   TotalValid
       WRITE(*,*)           'Arithmetic mean -->            ',   Arithmetic
       WRITE(*,*)           'Geometric mean -->             ',   Geometric
       WRITE(*,*)           'Harmonic mean   -->            ',   Harmonic
    ELSE
       WRITE(*,*)           'ERROR: none of the input is positive'
    END IF

END PROGRAM         ComputingMeans
Click                here          to                         download                   this                 program.



PROGRAM INPUT AND OUTPUT
The input consists of a number of real values, one on each line. The program will count the number of input data
items and ignore those illegal ones.

        If the input data is

         1.0
         2.0
         3.0
         4.0
         5.0
         6.0

         it will generate the following output. In this input, all data values are positive and none of them is ignored.
       Input    item    1   -->   1.
       Input    item    2   -->   2.
       Input    item    3   -->   3.
       Input    item    4   -->   4.
       Input    item    5   -->   5.
       Input    item    6   -->   6.

       # of items read -->             6
       # of valid items ->             6
       Arithmetic mean -->             3.5
       Geometric mean -->              2.99379516
       Harmonic mean   -->             2.44897938

      The following input contains a few illegal items. The third one is 3.o rather than 3.0. Thus, it is not a legal
       real value. The eighth item is #.$, which is not a number at all. Also, the sixth and tenth are non-positive.

         1.0
         2.0
         3.o
         4.0
         5.0
         -1.0
         7.0
         #.$
         9.0
         0.0

       The output is shown below. It correctly identifies all illegal data input items.

       Input item 1 --> 1.
       Input item 2 --> 2.
       ERROR: something wrong in your input
       Try again please
       Input item 4 --> 4.
       Input item 5 --> 5.
       Input item 6 --> -1.
       Input <= 0. Ignored
       Input item 7 --> 7.
       ERROR: something wrong in your input
       Try again please
       Input item 9 --> 9.
       Input item 10 --> 0.E+0
       Input <= 0. Ignored

       # of items read -->             10
       # of valid items ->             6
       Arithmetic mean -->             4.66666651
       Geometric mean -->              3.68892741
       Harmonic mean   -->             2.72236228


DISCUSSION
       The use of IOSTAT= follows closely the examples discussed in Handling End of File: READ Statement
        Revisited.
       This program uses an INTEGER variable IO to keep track the status of a read.
       If the value of IO is negative, end-of-file reached and the program exists the DO-loop.
       If the value of IO is positive, the previous READ had some problem. A message is displayed and asks the
        user to try again. In an interactive environment, this is a good practice.
       If the value of IO is zero, we have a normal situation. Then, the program checks further to see if the input
        is negative. This is exactly identical to a previous example and hence its discussion is omitted.


THE DO-CYCLE CONSTRUCT AND A PROGRAMMING EXAMPLE


In parallel with the DO-EXIT construct, Fortran has a DO-CYCLE construct as follows:

DO control-info
    statements-1
    CYCLE
    statements-2
END DO
where control-info is empty if the loop is a DO-END DO; otherwise, control-info contains all information that a
counting DO should have.

When the execution of a DO-loop encounters the CYCLE statement, the DO-loop starts next
iteration immediately.

This is not a recommended feature. So, if it is possible, do not use it.


EXAMPLES

       The following loop only displays 1, 2, 4 and 5. If the value of i is 1, 2, 4 or 5, the execution of the loop
        enters the ELSE part and displays the value of i. However, if i is 3, since i == 3 is .TRUE., the CYCLE
        statement is executed, which brings back to the beginning of the DO-loop starting the next iteration (i.e.,
        the iteration corresponds to i=4).

           INTEGER :: i

           DO i = 1, 5
              IF (i == 3) THEN
                  CYCLE
              ELSE
                  WRITE(*,*) i
              END IF
           END DO

       The following code has a DO-loop for processing the input value stored in Range. At the beginning of the
        loop, the value of Range is read in and checked. If the value is less than 2, the CYCLE statement brings the
        control back to the beginning of the loop to read a new value for Range. This will continue until a value
        that is greater than or equal to 2. Then, the logical expression of the IF-THEN-END IF is .FALSE. and
        consequently the execution continues with "... process Range ...".

           INTEGER :: Range

           DO
              WRITE(*,*) 'An integer >= 2 please --> '
              READ(*,*)    Range
              IF (Range < 2) THEN
                  WRITE(*,*) 'Input not in the required range'
                  CYCLE
              END IF
              ... process Range ...
           END DO

        Please compare this example with the technique used in the second prime number example in which EXIT
        is used rather than CYCLE.




A PROGRAMMING EXAMPLE
This problem solves a puzzle: RED x FOR = DANGER, where each letter represents a digit and different letters means
different digits. Moreover, R, F and D cannot be zero.

Write a program to find all solutions.


SOLUTION
!   ----------------------------------------------------------
!   This program solve the following puzzle:
!                   RED
!              x    FOR
!              -------
!                DANGER
!   where each distinct letter represents a different digit.
!   Moreover, R, F and D cannot be zero.
!   ----------------------------------------------------------

PROGRAM Puzzle
   IMPLICIT NONE

     INTEGER :: R, E, D, F, O, A, N, G                     ! the digits
     INTEGER :: RED, FOR, DANGER                           ! the constructed values
     INTEGER :: Count                                      ! solutions count

     WRITE(*,*)      'This program solves the following puzzle:'
     WRITE(*,*)
     WRITE(*,*)      '    RED'
     WRITE(*,*)      'x   FOR'
     WRITE(*,*)      '-------'
     WRITE(*,*)      ' DANGER'
     WRITE(*,*)
    Count = 0
    DO R = 1, 9
      DO E = 0, 9
        IF (E == R) CYCLE
        DO D = 1, 9
           IF (D == R .OR. D == E) CYCLE
           DO F = 1, 9
             IF (F == R .OR. F == E .OR. F == D) CYCLE
             DO O = 0, 9
               IF (O == R .OR. O == E .OR. O == D .OR.                                 &
                    O == F) CYCLE
               DO A = 0, 9
                  IF (A == R .OR. A == E .OR. A == D .OR.                              &
                      A == F .OR. A == O) CYCLE
                  DO N = 0, 9
                    IF (N == R .OR. N == E .OR. N == D .OR.                            &
                         N == F .OR. N == O .OR. N == A) CYCLE
                    DO G = 0, 9
                      IF (G == R .OR. G == E .OR. G == D .OR.                          &
                           G == F .OR. G == O .OR. G == A .OR.                         &
                           G == N) CYCLE
                      RED     = R*100 + E*10 + D
                      FOR     = F*100 + O*10 + R
                      DANGER = D*100000 + A*10000 + N*1000 + G*100                     + E*10 + R
                      IF (RED * FOR == DANGER) THEN
                          Count = Count + 1
                          WRITE(*,*) 'Solution ', Count, ':'
                          WRITE(*,*) '      RED = ', RED
                          WRITE(*,*) '      FOR = ', FOR
                          WRITE(*,*) ' DANGER = ', DANGER
                          WRITE(*,*)
                      END IF
                    END DO
                  END DO
               END DO
             END DO
           END DO
        END DO
      END DO
    END DO

END PROGRAM Puzzle
Click here to download this program.




PROGRAM OUTPUT
The following is the output generated by the above program. There are two solutions:

This program solves the following puzzle:

     RED
x    FOR
-------
  DANGER
Solution     1:
     RED     = 321
     FOR     = 563
  DANGER     = 180723

Solution     2:
     RED     = 481
     FOR     = 364
  DANGER     = 175084


DISCUSSION

      This program uses a brute-force method. That is, it searches all possibilities.
      Since there are eight digits, R, E, D, F, O, A, N and G, each of which runs from 0 to 9 except for R, F and D
       which runs from 1 to 9, we need eight nested DO-loops.
      Since different letters represent different digits, at the very beginning of a DO-loop, we must make sure
       the value of its control variable is different from the values of all previous loops.

         DO R = 1, 9
           DO E = 0, 9
             IF (E == R) CYCLE
             DO D = 1, 9
                IF (D == R .OR. D == E) CYCLE
                ... other loops ...
             END DO
           END DO
         END DO

       The above only shows three loops for R, E and D. At the beginning of the E loop, the value of E is checked
       to see if it is equal to the value of R. If they are equal, the CYCLE brings the control to the next iteration.
       Similarly, at the beginning of the D loop, the value of D is compared against the values of E and R. If they
       are equal, CYCLE causes the start of the next iteration. Note that D runs from 1 to 9.

      In the inner-most loop, the value of RED, FOR and DANGER are computed and compared. If RED*FOR is
       equal to DANGER, a solution is found and its values are displayed.

         RED     = R*100 + E*10 + D
         FOR     = F*100 + O*10 + R
         DANGER = D*100000 + A*10000 + N*1000 + G*100 + E*10 + R
         IF (RED * FOR == DANGER) THEN
             ... display READ, FOR and DANGER ...
         END IF

      The concept of this program, except for the use of CYCLE, is similar to that of finding all three-digit
       Armstrong Numbers. Please compare these two programs.

								
To top