Sei sulla pagina 1di 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

• One obvious way of writing this program is computing each term directly using the
formula xi/i!. However, this is not a wise way, since both xi 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:

Values for
u
v

21

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):
uva b c

21 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.

Potrebbero piacerti anche