Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
Computing Factorial
Computing EXP(x)
Armstrong Numbers
There are two forms of loops, the counting loop and the general loop. The syntax of the counting
loop is the following:
• INTEGER variables Counter, Init, Final and Step are control-var, initial-value, final-
value and step-size, respectively.
• 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.
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
INTEGER :: Count
DO Count = -3, 4, 2
WRITE(*,*) Count, Count*Count, Count*Count*Count
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
• 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.
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).
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.
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.
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
INTEGER :: a, b, c, d, e
• 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
You should not use this form of DO-loop in your programs. See the
discussion of general DO for the details.
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 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
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
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!
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
it will generate the following output. In this input, all data values are positive and
none of them is ignored.
• 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.
DISCUSSION
This example is quite simple and does not require further explanation.
COMPUTING FACTORIAL
PROBLEM STATEMENT
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
• If the input is -5, a negative number, the program generates the following output
indicating the input is wrong.
What is N in N! -->
-5
What is N in N! -->
0
0! = 1
What is N in N! -->
5
5! = 120
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!
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.
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
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
i = 5
DO
IF (i < -2) EXIT
WRITE(*,*) i
END DO
INTEGER :: i = 1, j = 5
DO
IF (j < 0) EXIT
WRITE(*,*) i
i = i + 1
END DO
INTEGER :: i
DO
IF (i <= 3) EXIT
WRITE(*,*) i
i = i - 1
END DO
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
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
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
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
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
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:
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
• 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.
The GCD is 32
• If the input values are 100 and 101, the GCD is 1 and 100 and 101 are relatively
prime.
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
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
• If the input value is -1, the output is a message saying the input is not legal.
Illegal input
2 is a prime
• If the input is 3, it is also a prime number.
3 is a prime
46 is NOT a prime
97 is 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.
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.
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.
• 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
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.
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
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.
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:
PROGRAM ClassAverage
IMPLICIT NONE
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.
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
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
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
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
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
WRITE(*,*)
WRITE(*,*) 'There are ', Count, ' primes in the range of 2 and ', Range
END PROGRAM Primes
• 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.
• The following is generated with input 100. There are 25 prime numbers 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:
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.
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
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
Factor # 1: 2
Factor # 2: 2
Factor # 3: 5
Factor # 4: 5
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.
Factor # 1: 53
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.
Divisor = 3
DO
IF (Divisor > Input) EXIT
...remove all factors of Divisor...
Divisor = Divisor + 2
END DO
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.
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
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.
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
1
3
4
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.
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
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.
• 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.
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.
EXAMPLES
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.
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
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
PROGRAM OUTPUT
The following is the output generated by the above program. There are two solutions:
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.
• 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.