Fortran 90 Tutorial
Fortran 90 Tutorial
Professor
Department of Computer Science
Michigan Technological University
o Fortran Basics
o Fortran Control Structures
o Fortran Subprograms
o Fortran Arrays
Program Structure
Your program should have the following form:
PROGRAM program-name
IMPLICIT NONE
[specification part]
[execution part]
[subprogram part]
END PROGRAM program-name
Here are some addition notes:
Fortran Comments
Comments should be used liberally to improve readability. The following are the rules for
making comments:
PROGRAM TestComment1
..........
READ(*,*) Year ! read in the value of Year
..........
Year = Year + 1 ! add 1 to Year
..........
END PROGRAM TestComment1
PROGRAM TestComment3
..........
READ(*,*) Count
The above is equivalent to the following, since the comment is ignored by the compiler:
• If the first non-blank character of the continuation line is &, continuation is to the first
character after the &:
A = 174.5 + ThisIsALong&
&VariableName * 123.45
is equivalent to
A = 174.5 + ThisIsALongVariableName * 123.45
In this case, there should be no spaces between the last character and the & on the first line.
For example,
is equivalent to
Note that there are spaces between ThisIsALong and VariableName. In this way, a token
(name and number) can be split over two lines. However, this is not recommended
FORTRAN ALPHABETS
Fortran only uses the following characters:
• Letters:
A B C D E F G H I J K L M
N O P Q R S T U V W X Y Z
a b c d e f g h i j k l m
n o p q r s t u v w x y z
• Digits:
0 1 2 3 4 5 6 7 8 9
• Special Characters:
space
' " ( ) * + - / : = _
! & $ ; < > % ? , .
FORTRAN CONSTANTS
Constants or more formally literal constants are the tokens used to denote the value of a
particular type. Fortran has five types of constants: integer, real, complex, logical, and
character string.
If single quote is used in a string, then double quotes should be used to enclose the
string:
"Lori's apple"
This string has content Lori's apple and length 12. Alternatively, you can write the
single quote twice as follows:
'Lori''s apple'
The compiler will treat a pair of single quotes in the content of a string as one. Thus,
the content of the above string is still Lori's apple.
o Correct Examples:
'What''s this?': content = What's this? and length = 11
'''''': content = '' and length = 2
o Incorrect Examples:
'Tech's seminar': the single quote between h and s should be written
twice.
FORTRAN IDENTIFIERS
A Fortran identifier must satisfy the following rules:
Except for strings, Fortran 90 is not case sensitive. Therefore, identifier Name is
identical to name, nAmE, NAme, NamE and namE. Similarly, PROGRAM is identical to
program, PROgram, and progRAM. In this course, all keywords such as PROGRAM, READ,
WRITE and END are in upper case and other identifiers use mixed cases.
type-specifier :: list
where the type-specifier is one of the following and list is a list of variable names separated
with commas:
Types INTEGER and REAL are easy. The following are examples:
Type CHARACTER is more involved. Since a string has a length attribute, a length value must be
attached to character variable declarations. There are two ways to do this:
Here, variables letter and digit can only hold no more than one character.
• If you want to declare character variables of different length with a single statement,
you can attach a length specification, *i, to the right of a variable. In this case, the
corresponding variable will have the indicated length and all other variables are not
affected.
• CHARACTER(LEN=10) :: City, Nation*20, BOX, bug*1
Here, variables City and BOX can hold a string of no more than 10 characters,
Nation can hold a string of no more than 20 characters, and bug can hold only one
character.
• There is one more way of specifying the length of a character variable. If the length
value is replaced with a asterisk *, it means the lengths of the declared variables are
determined elsewhere. In general, this type of declarations is used in subprogram
arguments or in PARAMETER and is refereed to as assumed length specifier.
• CHARACTER(LEN=*) :: Title, Position
Here, the actual lengths of variables Title and Position are unknown and will be
determined elsewhere.
• Add PARAMETER in front of the double colon (::) and use a comma to separate the
type name (i.e., REAL) and the word PARAMETER
• Following each name, one should add an equal sign (=) followed by an expression.
The value of this expression is then assigned the indicated name.
• After assigning a name to a value, one can use the name, rather than its value
throughout the program. The compiler would convert that name to its corresponding
value.
• It is important to note that the name assigned to a value is simply an alias of the
value. Therefore, that name is not a variable.
• After assigning a name to a value, that name can be used in a program, even in
subsequent type statements.
EXAMPLES:
• In the example blow, Limit is a name for the integer value 30, while Max_Count is a
name for the integer value 100:
• INTEGER, PARAMETER :: Limit = 30, Max_Count = 100
• In the example below, E is a name for the real value 2.71828, while PI is a name for
the real value 3.141592:
• REAL, PARAMETER :: E = 2.71828, PI = 3.141592
• In the example below, Total and Count are names for 10 and 5, respectively. The
name, Sum, is defined to be the product of the values of Total and Count and hence
Sum is the name for the value 50(=10*5).
• INTEGER, PARAMETER :: Total = 10, Count = 5, Sum = Total*Count
• In the example below, Name is a name for the string 'John' and State is a name for
the string "Utah"
• CHARACTER(LEN=4), PARAMETER :: Name = 'John', State = "Utah"
o If the string is longer, truncation to the right will happen. In the following case,
since the length of the string "Smith" is 5 while the length of Name is 4, the
string is truncated to the right and the content of Name is "Smit"
o CHARACTER(LEN=4), PARAMETER :: Name = 'Smith'
o If the string is shorter, spaces will be added to the right. Since the string "LA"
is of length 2 while the name City is of length 4, two spaces will be padded to
the right and the content of City becomes "LA "
o CHARACTER(LEN=4), PARAMETER :: City = "LA"
• This is where the assumed length specifier comes in. That is, Fortran allows the
length of character name to be determined by the length of s string. In the example
below, names Name and City are declared to have assumed length. Since the
lengths of 'John' and "LA" are 4 and 2, the length of the names Name and City are
4 and 2, respectively.
• CHARACTER(LEN=*), PARAMETER :: Name = 'John', City = "LA"
VARIABLES INITIALIZATION
A variable can be considered as a box that can hold a single value. However, initially the
content of a variable (or a box) is empty. Therefore, before one can use a variable, it must
receive a value. Do not assume the compiler or computer will put some value, say 0,
into a variable. There are at least three ways to put a value into a variable:
The way of initializing a variable is very similar to the use of PARAMETER attribute. More
precisely, do the following to initial a variable with the value of an expression:
Initializing a variable is only done exactly once when the computer loads your program into
memory for execution. That is, all initializations are done before the program starts its
execution. The use of un-initialized variables may cause unexpected result.
EXAMPLES:
• The following example initializes variables Offset to 0.1, Length to 10.0, and
tolerance to 1.E-7.
• The following example initializes variables State1 to "MI", State2 to "MN", and
State3 to "MD".
• The following example contains a mistake. While the compiler is processing the
initialization value for variable Received, the value of Period is unknown, although
it will be defined on the next line.
ARITHMETIC OPERATORS
Fortran has four types of operators: arithmetic, relational, logical, and character. The
following is a table of these operators, including their priority and associativity.
Associativ
Type Operator
ity
** right to left
Arithme
* / left to right
tic
+ - left to right
Relation
< <= > >= == /= none
al
• In the table, the operator on the top-most row (**) has the highest priority (i.e., it will
be evaluated first) while the operators on the bottom-most row (i.e., .EQV. and
.NEQV.) have the lowest priority. The operators on the same row have the same
priority. In this case, the order of evaluation is based on their associativity law.
• In addition to addition +, subtraction -, multiplication * and division /, Fortran has an
exponential operator **. Thus, raising X to the Y-th power is written as X**Y. For
example, the square of 5 is 5**2, and the square root of 5 is 5**0.5. The exponential
operator has the highest priority.
• Operators + and - can also be used as unary operators, meaning that they only need
one operand. For example, -A and +X. The former means change the sign of A, while
the latter is equivalent to X.
• Unary operators + and - have the same priority as their binary counterparts (i.e.,
addition + and subtraction -). As a result, since ** is higher than the negative sign -,
-3**2 is equivalent to -(3**2), which is -9.
• For arithmetic operators, the exponential operator ** is evaluated from right to left.
Thus, A**B**C is equal to A**(B**C) rather than (A**B)**C
In single mode arithmetic expressions, the result of an operation is identical to that of the
operands. The following is a table showing this fact. The empty entries will be discussed in
mixed mode arithmetic expressions.
Operato
INTEGER REAL
r
INTEGE mixed
INTEGER
R mode
mixed
REAL REAL
mode
SIMPLE EXAMPLES:
• 1 + 3 is 4
• 1.23 - 0.45 is 0.78
• 3 * 8 is 24
• 6.5/1.25 is 5.2
• 8.4/4.2 is 2.0 rather than 2, since the result must be of REAL type.
• -5**2 is -25
• 12/4 is 3
• 13/4 is 3 rather than 3.25. Since 13/4 is a single mode arithmetic expression and
since all of its operands are of INTEGER type, the result must also be of INTEGER
type. The computer will truncate the mathematical result (3.25) making it an integer.
Therefore, the result is 3.
• 3/5 is 0 rather than 0.6.
The following are rules of evaluating a more complicated single mode arithmetic expression:
o if the next one is equal to the current, the associativity rules are used to
determine which one should be evaluated. For example, if both the current
and the next operators are *, then 3 * 8 * 6 will be evaluated as (3 * 8) * 6.
On the other hand, if the operator is **, A ** B ** C will be evaluated as A **
(B ** C).
o if the next one is higher than the current, the scan should continue with the
next operator. For example, consider the following expression:
o 4 + 5 * 7 ** 3
if the current operator is +, since the next operator * has higher priority, the
scan continues to *. Once the scan arrives at *, since the next operator ** is
higher, 7 ** 3 is evaluated first, transforming the given expression to
4 + 5 * 343
Then, the new expression is scan again. The next operator to be evaluated is
*, followed by +. Thus, the original expression is evaluated as 4 + (5 * (7 **
3)).
In the following examples, brackets are used to indicated the order of evaluation.
• The result is 4 rather than 4.444444 since the operands are all integers.
2 * 4 * 5 / 3 ** 2
--> [2 * 4] * 5 / 3 ** 2
--> 8 * 5 / 3 ** 2
--> [8 * 5] / 3 ** 2
--> 40 / 3 ** 2
--> 40 / [3 ** 2]
--> 40 / 9
--> 4
In mixed mode arithmetic expressions, INTEGER operands are always converted to REAL
before carrying out any computations. As a result, the result of a mixed mode expression is of
REAL type. The following is a table showing this fact.
The rules for evaluating mixed mode arithmetic expressions are simple:
• Use the rules for evaluating single mode arithmetic expressions for scanning.
• After locating an operator for evaluation, do the following:
o if the operands of this operator are of the same type, compute the result of
this operator.
o otherwise, one of the operand is an integer while the other is a real number.
In this case, convert the integer to a real (i.e., adding .0 at the end of the
integer operand) and compute the result. Note that since both operands are
real numbers, the result is a real number.
• There is an exception, though. In a**n, where a is a real and n is a positive
integer, the result is computed by multiplying n copies of a. For example, 3.5**3 is
computed as 3.5*3.5*3.5
SIMPLE EXAMPLES:
• 1 + 2.5 is 3.5
• 1/2.0 is 0.5
• 2.0/8 is 0.25
• -3**2.0 is -9.0
• 4.0**(1/2) is first converted to 4.0**0 since 1/2 is a single mode expression whose
result is 0. Then, 4.0**0 is 1.0
AN IMPORTANT NOTE:
In expression a**b where a is REAL, the result is undefined if the value of a is
negative. For example, -4.0**2 is defined with -16.0 as its result, while (-4.0)**2 is
undefined.
• Note that 6.0 ** 2 is not converted to 6.0 ** 2.0. Instead, it is computed as 6.0 *
6.0.
5 * (11.0 - 5) ** 2 / 4 + 9
--> 5 * (11.0 - {5}) ** 2 / 4 + 9
--> 5 * (11.0 - 5.0) ** 2 / 4 + 9
--> 5 * ([11.0 - 5.0]) ** 2 / 4 + 9
--> 5 * 6.0 ** 2 / 4 + 9
--> 5 * [6.0 ** 2] / 4 + 9
--> 5 * 36.0 / 4 + 9
--> {5} * 36.0 / 4 + 9
--> 5.0 * 36.0 / 4 + 9
--> [5.0 * 36.0] / 4 + 9
--> 180.0 / 4 + 9
--> 180.0 / {4} + 9
--> 180.0 / 4.0 + 9
--> [180.0 / 4.0] + 9
--> 45.0 + 9
--> 45.0 + {9}
--> 45.0 + 9.0
--> 54.0
25.0 ** 1 / 2 * 3.5 ** (1 / 3)
--> [25.0 ** 1] / 2 * 3.5 ** (1 / 3)
--> 25.0 / 2 * 3.5 ** (1 / 3)
--> 25.0 / {2} * 3.5 ** (1 / 3)
--> 25.0 / 2.0 * 3.5 ** (1 / 3)
--> 12.5 * 3.5 ** (1 / 3)
--> 12.5 * 3.5 ** ([1 / 3])
--> 12.5 * 3.5 ** 0
--> 12.5 * [3.5 ** 0]
--> 12.5 * 1.0
--> 12.5
Click here to continue with single mode arithmetic expressions.
variable = expression
Its purpose is saving the result of the expression to the right of the assignment operator to
the variable on the left. Here are some rules:
• The expression is evaluated first with the rules discussed in the single mode or the
mixed mode expressions pages.
• If the type of the expression is identical to that of the variable, the result is saved in
the variable.
• Otherwise, the result is converted to the type of the variable and saved there.
o If the type of the variable is INTEGER while the type of the result is REAL, the
fractional part, including the decimal point, is removed making it an integer
result.
o If the type of the variable is REAL while the type of the result is INTEGER,
then a decimal point is appended to the integer making it a real number.
• Once the variable receives a new value, the original one disappears and is no more
available.
• CHARACTER assignment follows the rules stated in the discussion of the
PARAMETER attribute.
EXAMPLES:
• The program segment below declares three INTEGER variables. The first assignment
statement saves an integer value to variable Unit. The second saves a real number
100.99 into variable Amount. However, since Amount is an INTEGER variable, the
real value 100.99 is converted to an integer, 100, and saved into Amount. Thus,
after the second assignment completes, variable Amount holds 100. The third
assignment computes the single mode expression, yielding a result 500 = 5*100.
Thus, variable Total receives 500.
Unit = 5
Amount = 100.99
Total = Unit * Amount
Radius = 5
Area = (Radius ** 2) * PI
The meaning of the first assignment is computing the sum of the value in Counter and 1,
and saves it back to Counter. Since Counter's current value is zero, Counter + 1 is 1+0
= 1 and hence 1 is saved into Counter. Therefore, the new value of Counter becomes 1
and its original value 0 disappears.
The second assignment statement computes the sum of Counter's current value and 3,
and saves the result back to Counter. Thus, the new value of Counter is 1+3=4.
INTEGER :: Counter = 0
Counter = Counter + 1
Counter = Counter + 3
• The following swaps the values in A and B, with the help of C. That is, after
completing the following three assignment statements, A and B have 5 and 3,
respectively.
The second assignment statements puts B's value into A. This destroys A's original value
3. After this, A = 5, B = 5 and C = 3.
The third assignment statement puts C's value into B. This makes A=5, B=3 and C=3.
Therefore, the values in A and B are exchanged.
INTEGER :: A = 3, B = 5, C
C = A
A = B
B = C
The following is another possible solution; but, it uses one more variable.
INTEGER :: A = 3, B = 5, C, D
C = A
D = B
A = D
B = C
AN IMPORTANT NOTE:
A name declared with the PARAMETER attribute is an alias of a value and is not a
variable. Therefore, it cannot be used on the left-hand side of =, although it can
be used on the right-hand side. The following is wrong!
InchToCM = factor * X
• the name and meaning of the function such as ABS() and SQRT()
• the number of arguments
• the range of the argument
• the types of the arguments
• the type of the return value or the function value
For example, function SQRT() accepts a REAL argument whose value must be non-negative
and computes and returns the square root of the argument. Therefore, SQRT(25.0) returns
the square root of 25.0 and SQRT(-1.0) would cause an error since the argument is
negative.
• Mathematical functions:
Functi Arg. Return
Meaning
on Type Type
SQRT(
square root of x REAL REAL
x)
tangent of x
TAN(x) REAL REAL
radian
ASIN(x
arc sine of x REAL REAL
)
ACOS(
arc cosine of x REAL REAL
x)
ATAN(
arc tangent of x REAL REAL
x)
natural logarithm
LOG(x) REAL REAL
of x
• Note that all trigonometric functions use radian rather than degree for measuring angles.
For function ATAN(x), x must be in (-PI/2, PI/2). For ASIN(x) and ACOS(x), x must be
in [-1,1].
• Conversion functions:
Arg. Return
Function Meaning
Type Type
FRACTION
the fractional part of x REAL REAL
(x)
INTEGE
REAL(x) convert x to REAL REAL
R
• Other functions:
Arg. Return
Function Meaning
Type Type
INTEGE
INTEGER
MAX(x1, maximum of x1, x2, R
x2, ..., xn) ... xn
REAL REAL
INTEGE
INTEGER
MIN(x1, minimum of x1, R
x2, ..., xn) x2, ... xn
REAL REAL
INTEGE
INTEGER
remainder x - R
MOD(x,y)
INT(x/y)*y
REAL REAL
FUNCTIONS IN AN EXPRESSION:
AN EXAMPLE:
The example below has three initialized variables A, B and C. The result is computed and saved
into uninitialized variable R.
The first form starts with READ(*,*), followed by a list of variable names, separated by
commas. The computer will read values from the keyboard successively and puts the value into
the variables. The second form only has READ(*,*), which has a special meaning.
• The following example reads in four values into variables Factor, N, Multiple and
tolerance in this order.
• INTEGER :: Factor, N
• REAL :: Multiple, tolerance
•
• READ(*,*) Factor, N, Multiple, tolerance
• The following example reads in a string into Title, followed by three real numbers
into Height, Length and Area.
• CHARACTER(LEN=10) :: Title
• REAL :: Height, Length, Area
•
• READ(*,*) Title, Height, Length, Area
• If a READ statement needs some input values, start a new line that contains the
input. Make sure the type of the input value and the type of the corresponding
variable are the same. The input data values must be separated by space or
commas.
CHARACTER(LEN=5) :: Name
REAL :: height, length
INTEGER :: count, MaxLength
Note that all input data are on the same line and separated with spaces. After
reading in this line, the contents of the variables are
Name "Smith"
height 100.0
count 25
length 123.579
MaxLength 100000
• Input values can be on several lines. As long as the number of input values and the
number of variables in the corresponding READ agree, the computer will search for
the input values. Thus, the following input should produce the same result. Note that
even blank lines are allowed in input.
"Smith" 100.0
25
123.579
10000
• The execution of a READ always starts searching for input values with a new input
line.
INTEGER :: I, J, K, L, M, N
READ(*,*) I, J
READ(*,*) K, L, M
READ(*,*) N
If the above READ statements are used to read the following input lines,
100 200
300 400 500
600
then I, J, K, L, M and N will receive 100, 200, 300, 400, 500 and 600, respectively.
• Consequently, if the number of input values is larger than the number of variables in
a READ statement, the extra values will be ignored. Consider the following:
INTEGER :: I, J, K, L, M, N
READ(*,*) I, J, K
READ(*,*) L, M, N
But, if the input value is a real number and the corresponding variable is of INTEGER
type, an error will occur.
The length of the input string and the length of the corresponding CHARACTER
variable do not have to be equal. If they are not equal, truncation or padding with spaces
will occur as discussed in the PARAMETER attribute page.
• Finally, a READ without a list of variables simply skips a line of input. Consider the
following:
INTEGER :: P, Q, R, S
READ(*,*) P, Q
READ(*,*)
READ(*,*) R, S
The first READ reads 100 and 200 into P and Q and 300 is lost. The second READ
starts with a new input line, which is the second one. It does not read in anything.
The third READ starts with the third line and reads 700 and 800 into R and S. As a
result, the three input values (i.e., 400, 500 and 600) are all lost. The third value on
the third line, 900, is also lost.
The first form starts with WRITE(*,*), followed by a list of arithmetic expressions or character
strings, separated by commas. The computer will evaluate the arithmetic expressions and
displays the results. Note that if a variable does not contain a value, its displayed result is
unpredictable. The second form only has WRITE(*,*), which has a special meaning.
INTEGER :: Factor, N
REAL :: Multiple, tolerance
• The following example displays the string content of Title, followed by the result of
(Height + Length) * Area.
CHARACTER(LEN=10) :: Title
REAL :: Height, Length, Area
INTEGER :: Target
REAL :: Angle, Distance
CHARACTER(LEN=*), PARAMETER :: Time = "The time to hit target " &
IS = " is " &
UNIT = " sec."
Target = 10
Angle = 20.0
Distance = 1350.0
WRITE(*,*) 'Angle = ', Angle
WRITE(*,*) 'Distance = ', Distance
WRITE(*,*)
WRITE(*,*) Time, Target, IS, Angle * Distance, UNIT
Angle = 20.0
Distance = 1350.0
The above example uses assumed length specifier (i.e., LEN=*) and continuation lines
(i.e., symbol &).
• If there are too many results that cannot be fit into a single line, the computer will
display remaining results on the second, the third line and so on.
OUTPUT FORMAT:
There is nothing to worry about the output format. The computer will use the best way to
display the results. In other words, integers and real numbers will be displayed as integers and
real numbers. But, only the content of a string will be displayed. The computer will also
guarantee that all significant digits will be shown so that one does not have to worry how many
positions should be used for displaying a number. The consequence is that displaying a good-
looking table is a challenge. This will be discussed in FORMAT statement.
PROGRAMMING EXAMPLE: THREE PROGRAMMING TRAPS
PROBLEM STATEMENT
The purpose of this program is to show you three common programming traps:
SOLUTION
! ------------------------------------------------------------
! This program illustrates the following points:
! (1) The exponential trap:
! That is, A**B**C is equal to A**(B**C) rather
! than (A**B)**C.
! (2) The integer division trap:
! That is, 4/6 is ZERO in Fortran rather than
! a real number 0.666666
! Function REAL() is used to illustrate the
! differences.
! (3) The string truncation trap:
! What if the length assigned to a CHARACTER
! is shorter than the length of the string you
! expect the identifier to have? The third part
! shows you the effect.
! ------------------------------------------------------------
PROGRAM Fortran_Traps
IMPLICIT NONE
INTEGER, PARAMETER :: A = 2, B = 2, H = 3
INTEGER, PARAMETER :: O = 4, P = 6
CHARACTER(LEN=5), PARAMETER :: M = 'Smith', N = 'TEXAS'
CHARACTER(LEN=4), PARAMETER :: X = 'Smith'
CHARACTER(LEN=6), PARAMETER :: Y = 'TEXAS'
PROGRAM OUTPUT
First, the exponential trap:
2 ** 2 ** 3 = 256
( 2 ** 2 ) **3 = 64
2 ** ( 2 ** 3 ) = 256
4 / 6 = 0
REAL( 4 ) / 6 = 0.666666687
4 / REAL( 6 ) = 0.666666687
DISCUSSION
On the second line, it is easily seen that the original Smith becomes Smit and the original
TEXAS becomes TEXAS_, where _ indicates a space.
PROBLEM STATEMENT
Given three real numbers, its arithmetic mean (average), geometric mean and harmonic mean are
defined as follows:
Write a program to compute and display the means of three REAL variables initialized with
positive real values.
SOLUTION
! -------------------------------------------------------
! Computes arithmetic, geometric and harmonic means
! -------------------------------------------------------
PROGRAM ComputeMeans
IMPLICIT NONE
ArithMean = (X + Y + Z)/3.0
GeoMean = (X * Y * Z)**(1.0/3.0)
HarmMean = 3.0/(1.0/X + 1.0/Y + 1.0/Z)
Arithmetic mean = 2.
Geometric mean = 1.81712067
Harmonic Mean = 1.63636363
DISCUSSION
• Variables X, Y and Z are initialized in the first REAL statement, while the second
declares three variables, ArithMean, GeoMean and HarmMean, for holding the
result.
• The first WRITE statement displays the values of X, Y and Z. The second WRITE
generates a blank line.
• In the second assignment statement that computes the geometric mean, the
exponent part is 1.0/3.0 instead of 1/3, since the latter is zero. 1.0/3 and 1.0/3 also
work fine. But, you should not use 0.3, since it is not equal to 1/3.
PROBLEM STATEMENT
if b*b-4*a*c is non-negative, the roots of the equation can be computed with the following
formulae:
Write a program to read in the coefficients a, b and c, and compute and display the roots. You
can assume that b*b - 4*a*c is always non-negative.
SOLUTION
! ---------------------------------------------------
! Solve Ax^2 + Bx + C = 0 given B*B-4*A*C >= 0
! ---------------------------------------------------
PROGRAM QuadraticEquation
IMPLICIT NONE
REAL :: a, b, c
REAL :: d
REAL :: root1, root2
d = SQRT(b*b - 4.0*a*c)
WRITE(*,*)
WRITE(*,*) 'Roots are ', root1, ' and ', root2
PROGRAM OUTPUT
A, B, C Please :
1.0 -5.0 3.0
The input to the above problem consists of three real numbers, 1.0, -5.0 and 3.0, and the
computed roots are 4.30277538 and 0.697224379.
DISCUSSION
After displaying this message, the computer executes READ. Since there is no input
value, it will wait until the user types in three real values and hits the Return key.
Then, these values are stored in a, b and c.
• The first assignment statement computes the square root of the discriminant (i.e.,
b*b - 4.0*a*c) and stores it into variable d.
• The roots are computed with the second and third assignments. Note that the
parenthesis surrounding 2.0*a cannot be removed; otherwise, it is equivalent to ((-b
+ d)/2.0)*a, which is wrong.
• The last two WRITE statements display the roots.
PROBLEM STATEMENT
Given base b and height h, the length of a special segment on a parabola can be computed as
follows:
Write a program to read in the values of base and height, and use the above formula to compute
the length of the parabola segment. Note that both base and height values must be positive.
SOLUTION
! -----------------------------------------------------------
! Calculate the length of a parabola given height and base.
*
! -----------------------------------------------------------
PROGRAM ParabolaLength
IMPLICIT NONE
t = 2.0 * Height
temp = SQRT(t**2 + Base**2)
Length = temp + Base**2/t*LOG((t + temp)/Base)
WRITE(*,*)
WRITE(*,*) 'Height = ', Height
WRITE(*,*) 'Base = ', Base
WRITE(*,*) 'Length = ', Length
PROGRAM OUTPUT
Height of a parabola :
100.0
Base of a parabola :
78.5
Height = 100.
Base = 78.5
Length = 266.149445
The input values for Height and Base are 100.0 and 78.5, respectively. The computed length is
266.149445.
DISCUSSION
• The values of base and height will be stored in REAL variables Base and Height,
respectively. Length will be used to store the parabola segment length.
• Since the content in the square root is used twice, it would be more convenient to
save the result in a variable. This value will be stored in temp. Since 2h also appears
a few times, variable t is used to store this value. After reading in Height and Base,
2.0 * Height is computed and stored in t with the first assignment. Then, the second
assignment computes the content in the square root and stores the result into temp.
• The third assignment compute the segment length and stores the result into Length.
Note that intrinsic function LOG() is used.
• The four WRITE statements display the input and the results.
PROBLEM STATEMENT
This program computes the position (x and y coordinates) and the velocity (magnitude and
direction) of a projectile, given t, the time since launch, u, the launch velocity, a, the initial angle
of launch (in degree), and g=9.8, the acceleration due to gravity.
The horizontal and vertical displacements are given by the following formulae:
The horizontal and vertical components of the velocity vector are computed as
Finally, the angle between the ground and the velocity vector is determined by the formula
below:
Write a program to read in the launch angle a, the time since launch t, and the launch velocity u,
and compute the position, the velocity and the angle with the ground.
SOLUTION
! --------------------------------------------------------------------
! Given t, the time since launch, u, the launch velocity, a, the
! initial angle of launch (in degree), and g, the acceleration due to
! gravity, this program computes the position (x and y coordinates)
! and the velocity (magnitude and direction) of a projectile.
! --------------------------------------------------------------------
PROGRAM Projectile
IMPLICIT NONE
PROGRAM OUTPUT
If the input to the program consists of the following three real values:
DISCUSSION
• The program uses Angle for the angle a, Time for t, and U for u. The READ
statement reads the input.
• The first assignment statement converts the angle in degree to radian. This is
necessary since all intrinsic trigonometric functions use radian rather than degree.
• Variables X and Y, which are computed in the second and third assignments, hold the
displacements.
• The next two assignments compute the components of the velocity vector.
• The velocity itself is computed in the sixth assignment.
• Finally, the angle with ground, Theta, is computed with the last assignment. Note
that ithe result is converted back to degree, since ATAN(x) returns the arc tangent
value of x in radian.
• Variable Ans1 contains a string "JohnLori**", where * denotes a space. These two
spaces come from variable Lori since its content is "Lori**".
• Variable Ans2 contains a string "Sam Reagan". The space in the string comes from
variable Sam since its content is "Sam*", where, as above, * denotes a space.
• Variable Ans3 contains a string "ReaganSam*".
• Variable Ans4 contains a string "Lori**Sam*".
SUBSTRINGS
A consecutive part of a string is called a substring. One can append the extent specifier
at the end of a CHARACTER variable to indicate a substring. An extent specifier has a form
of
( integer-exp1 : integer-exp2 )
It starts with a (, followed by an integer expression, followed by a colon :, followed by
another integer expression, followed by ). The first integer indicates the first position of the
substring, while the second integer indicates the last position of the substring. Therefore,
(3:5) means the substring consists of the third, fourth and fifth characters. If the content of
variable String is "abcdefghijk", then String(3:5) is a string "cde".
If the first integer expression is missing, the value is assumed to be 1. If the second integer
expression is missing, the value is assumed to be the last character of the string. Continue with
the example in previous paragraph. String(:4) is string "abcd". String(2+5:) is string "ghijk".
As a good programming practice, the value of the first integer expression should be greater than
or equal to 1, and the value of the second integer expression should be less than of equal to the
length of the string.
A string variable with an extent specifier can be used on the left-hand side of an assignment. Its
meaning is assigning the string content on the right-hand side into the substring part of the string
variable. Let the content of a string variable LeftHand of length 10 be "1234567890". The
following are a few examples:
• LeftHand(3:5) = "abc": the new content of LeftHand is "12abc67890".
• LeftHand(1:6) = "uvwxyz": the new content of LeftHand is "uvwxyz7890".
• LeftHand(:6) = "uvzxyz": the result is identical to the previous example.
• LeftHand(4:) = "lmnopqr": the new content of LeftHand is "123lmnopqr".
• LeftHand(3:8) = "abc": the new content of LeftHand is "12abc***90", where *
denotes a space. Note that since LeftHand(3:8) consists of 6 character positions
and "abc" has only three characters, the remaining will be filled with spaces.
• LeftHand(4:7) = "lmnopq": the new content of LeftHand is "123lmno890". It is
due to truncation.
EXAMPLE
! ----------------------------------------------------------------
! This program uses DATE_AND_TIME() to retrieve the system date
! and the system time. Then, it converts the date and time
! information to a readable format. This program demonstrates
! the use of concatenation operator // and substring
! ----------------------------------------------------------------
PROGRAM DateTime
IMPLICIT NONE
Year = DateINFO(1:4)
Month = DateINFO(5:6)
Day = DateINFO(7:8)
Hour = TimeINFO(1:2)
Minute = TimeINFO(3:4)
Second = TimeINFO(5:10)
WRITE(*,*)
WRITE(*,*) 'Time Information -> ', TimeINFO
WRITE(*,*) ' Hour -> ', Hour
WRITE(*,*) ' Minite -> ', Minute
WRITE(*,*) ' Second -> ', Second
WRITE(*,*) ' Pretty Time -> ', PrettyTime
WRITE(*,*)
WRITE(*,*) ' Pretty Time -> ', PrettyTime
PROGRAM OUTPUT
Date information -> 19970811
Year -> 1997
Month -> 08
Day -> 11
DISCUSSION
• Subroutine DATE_AND_TIME() returns the date of time and day information into two
character arguments. The first one, DateINFO, must have a length of at least 8. The
returned value is in the form of ccyymmdd, where cc gives the century, yy the year,
mm the month, and dd the day. If today is August 11, 1997, the call to this
subroutine returns a string of eight characters "19970811"
• The second argument, TimeINFO, will receive a string of 12 characters with a form
of hhmmss.sss, where hh gives the hour value, mm the minute value, and ss.sss
the second value. Thus, if the time this subroutine is called is 1 after 7 minutes and
17.620 seconds, the returned value is "010717.620"
AKHIR PERTEMUAN 1
SELECTIVE EXECUTION
Relational Operators
Form 1: IF-THEN-ELSE-END IF
Form 2: IF-THEN-END IF
Form 3: Logical IF
Nested IF-THEN-ELSE-END IF
LOGICAL values are either true or false. In Fortran, they must be written as .TRUE. and
.FALSE. Note that the two periods surrounding TRUE and FALSE must be there; otherwise,
they become identifiers.
A variable that can hold one of the logical values is a logical variable and it is of type
LOGICAL. To declare a LOGICAL variable, do it as what you did for INTEGER and REAL
variables. But, use the type name LOGICAL instead.
LOGICAL constants can have aliases declared with the PARAMETER attribute.
LOGICAL variables can be initialized when they are declared and can be assigned a logical
value.
However, a LOGICAL variable can only hold a logical value. Putting a value of any other type
(e.g., INTEGER or REAL) into a LOGICAL variable will cause an error.
The following are examples:
• Answer, Condition, Test, Value and Yes_and_No are LOGICAL variables that
can hold either .TRUE. or .FALSE.:
• LOGICAL identifiers Answer and Condition are aliases of .TRUE. and .FALSE.,
respectively:
• LOGICAL variables Test and PreTest are initialized to .TRUE. and .FALSE.,
respectively:
• LOGICAL variables Cond_1, Cond_2 and Total are assigned with .TRUE.,
.TRUE. and .FALSE., respectively:
Cond_1 = .TRUE.
Cond_2 = .TRUE.
Total = .FALSE.
LOGICAL INPUT AND OUTPUT
When using WRITE(*,*) to display a LOGICAL value, Fortran displays .TRUE. and .FALSE.
with T and F, respectively.
When preparing input for READ(*,*), use T and F for .TRUE. and .FALSE., respectively.
RELATIONAL OPERATORS
• Each of these six relational operators takes two operands. These two operands must
both be arithmetic or both be strings. For arithmetic operands, if they are of different
types (i.e., one INTEGER and the other REAL), the INTEGER operand will be
converted to REAL.
• The outcome of a comparison is a LOGICAL value. For example, 5 /= 3 is
.TRUE. and 7 + 3 >= 20 is .FALSE.
• All relational operators have equal priority and are lower than those of
arithmetics operators as shown in the table below:
Associativ
Type Operator
ity
** right to left
Arithme
* / left to right
tic
+ - left to right
EXAMPLES
A < B < C < D < E < F < G < H < I < J < K < L < M
< N < O < P < Q < R < S < T < U < V < W < X < Y < Z
a < b < c < d < e < f < g < h < i < j < k < l < m
< n < o < p < q < r < s < t < u < v < w < x < y < z
• The comparison always starts at the first character and proceeds from left
to right.
• If the two corresponding characters are equal, then proceed to the next
pair of characters.
• Otherwise, the string containing the smaller character is considered to be
the smaller one. And, the comparison halts.
• During the process comparison, if
o both strings have consumed all of their characters, they are equal
since all of their corresponding characters are equal.
o otherwise, the shorter string is considered to be the smaller one.
EXAMPLES
a b c d e f
= = = <
a b c e f g
The first three characters of both strings are equal. Since 'd' of the first
string is smaller than 'e' of the second, "abcdef" < "abcefg" holds.
Since all compared characters are equal and the first string is shorter,
"01357" < "013579" holds.
D O G
<
F O X
The first character (i.e., 'D' < 'F') determines the outcome. That is, "DOG" <
"FOX" yields .TRUE.
A SPECIAL NOTE
The priority of all six relational operators is lower than the string concatenation
operator //. Therefore, if a relational expression involves //, then all string
concatenations must be carried out before evaluating the comparison operator.
Here is an example:
Fortran has five LOGICAL operators that can only be used with expressions whose results are
logical values (i.e., .TRUE. or .FALSE.). All LOGICAL operators have priorities lower than
arithmetic and relational operators. Therefore, if an expression involving arithmetic, relational
and logical operators, the arithmetic operators are evaluated first, followed by the relational
operators, followed by the logical operators.
The following is a table of these operators, including there priority and associativity.
Associativ
Type Operator
ity
** right to left
Arithme
* / left to right
tic
+ - left to right
TRUTH TABLES
The evaluation of logical expressions is determined by truth tables. Let us start with the
.NOT. operator.
Opera
Result
nd
. .
NOT .TRUE. FALSE
. .
. .
FALSE. TRUE.
Note that .NOT. is a unary operator. Therefore, .NOT. a yields .TRUE. (resp., .FALSE.) if the
value of LOGICAL variable a is .FALSE. (resp., .TRUE.).
. .
.
TRUE FALSE
TRUE.
. .
. . .
FALS FALS FALSE
E. E. .
Therefore, the result of logical expression a .AND. b is .TRUE. if and only if both operands a
and b are .TRUE.. In all other cases, the result is always .FALSE.
.
.
.OR. TRUE
FALSE
.
.
. .
TRUE
TRUE. TRUE.
.
. . .
FALS TRUE FALSE
E. . .
Therefore, the result of logical expression a .OR. b is .FALSE. if and only if both operands a
and b are .FALSE.. In all other cases, the result is always .TRUE. In other words, if one of the
two operands of the .OR. operator is .TRUE., the result is .TRUE.
.
.
.EQV. TRUE
FALSE
.
. .
.
TRUE FALSE
TRUE.
. .
. . .
FALS FALS
TRUE.
E. E.
Therefore, the result of logical expression a .EQV. b is .TRUE. if and only if both operands a
and b have the same value (i.e., both are .TRUE. or both are .FALSE.). As mentioned in
relational expressions, relational operators can only compare arithmetic values and cannot be
used to compare logical values. To compare if two logical values are equal, use .EQV.
. .
.
NEQV TRUE
FALSE
. .
.
. .
FALS
TRUE. TRUE.
E.
. . .
FALS TRUE FALSE
E. . .
Therefore, the result of logical expression a .NEQV. b is .TRUE. if and only if both operands a
and b do not have the same value. As mentioned in relational expressions, relational operators
can only compare arithmetic values and cannot be used to compare logical values. To compare if
two logical values are not equal, use .NEQV. Note that .NEQV is the opposite of .EQV.. Hence,
to test if logical variables x and y have different values, one can use .NOT. (x .EQV. y). Here, if
x and y have the same value, x .EQV. y is .TRUE. and .NOT. (x .EQV. y) is .FALSE. On the
other hand, if x and y have different values, x .EQV. y is .FALSE. and .NOT. (x .EQV. y) is
.TRUE.
PRIORITY
The priority of .NOT. is the highest, followed by .AND., followed by .OR., followed by .EQV.
and .NEQV. Note that .NOT. is right associative, while the other four are left associative.
• Let LOGICAL variables Something and Another have values .TRUE. and .FALSE.,
respectively.
• Let LOGICAL variables a, b and c have values .TRUE., .TRUE. and .FALSE.,
respectively.
Note that the above expression, if you like, can be rewritten with parentheses as
follows:
ASSIGNMENTS
The result of a logical expression can be assigned into a LOGICAL variable. Note that only
logical values can be put into LOGICAL variables. The follow assignments save the results of
the examples into LOGICAL variables:
Thus, Result1, Result2, Result3 and Results receive .FALSE., .FALSE., .TRUE. and
.FALSE., respectively.
IF-THEN-ELSE-END IF
IF (logical-expression) THEN
statements-1
ELSE
statements-2
END IF
where statements-1 and statements-2 are sequences of executable statements, and logical-
expression is a logical expression. The execution of this IF-THEN-ELSE-END IF statement
goes as follows:
EXAMPLES
• The following code first reads in an integer into INTEGER variable Number. Then, if
Number can be divided evenly by 2 (i.e., Number is a multiple of 2), the
WRITE(*,*) between IF and ELSE is executed and shows that the number is even;
otherwise, the WRITE(*,*) between ELSE and END IF is executed and shows that
the number is odd. Function MOD(x,y) computes the remainder of x divided by y.
This is the the remainder (or modulo) function
INTEGER :: Number
READ(*,*) Number
IF (MOD(Number, 2) == 0) THEN
WRITE(*,*) Number, ' is even'
ELSE
WRITE(*,*) Number, ' is odd'
END IF
• The following program segment computes the absolute value of X and saves the
result into variable Absolute_X. Recall that the absolute value of x is x if x is non-
negative; otherwise, the absolute value is -x. For example, the absolute value of 5 is
5 and the absolute value of -4 is 4=-(-4). Also note that the WRITE(*,*) statement
has been intentionally broken into two lines with the continuation line symbol &.
REAL :: X, Absolute_X
X = .....
IF (X >= 0.0) THEN
Absolute_X = X
ELSE
Absolute_X = -X
END IF
WRITE(*,*) 'The absolute value of ', x, &
' is ', Absolute_X
• The following program segment reads in two integer values into a and b and finds
the smaller one into Smaller. Note that the WRITE(*,*) has also been broken into
two lines.
INTEGER :: a, b, Smaller
READ(*,*) a, b
IF (a <= b) THEN
Smaller = a
ELSE
Smaller = b
END IF
Write(*,*) 'The smaller of ', a, ' and ', &
b, ' is ', Smaller
A USEFUL TIP
You may find the following way of organizing IF-THEN-ELSE-END IF very useful, especially
when your program logic is reasonably complex.
Draw a rectangular box and a vertical line dividing the box into two parts. Then, write down the
logical expression in the left part and draw a horizontal line dividing the right parts into two
smaller ones. The upper rectangle is filled with what you want to do when the logical expression
is .TRUE., while the lower rectangle is filled with what you want to do when the logical
expression is .FALSE.:
For example, the third example above has the following description:
a is the smaller
number
a <=
b
b is the smaller
number
Although this is an easy example, you will sense its power when you will be dealing with more
complex problems.
IF-THEN-END IF
IF (logical-expression) THEN
statements
END IF
where statements is a sequence of executable statements, and logical-expression is a
logical expression. The execution of this IF-THEN-ELSE-END IF statement goes as follows:
EXAMPLES
• The following program segment computes the absolute value of X and saves the
result into variable Absolute_X. Recall that the absolute value of x is x if x is non-
negative; otherwise, the absolute value is -x. For example, the absolute value of 5 is
5 and the absolute value of -4 is 4=-(-4). Also note that the WRITE(*,*) statement
has been intentionally broken into two lines with the continuation line symbol &. The
trick is that the value of X is first saved to Absolute_X whose value is changed later
only if the value of X is less than zero.
REAL :: X, Absolute_X
X = .....
Absolute_X = X
IF (X < 0.0) THEN
Absolute_X = -X
END IF
WRITE(*,*) 'The absolute value of ', x, &
' is ', Absolute_X
• The following program segment reads in two integer values into a and b and finds
the smaller one into Smaller. Note that the WRITE(*,*) has also been broken into
two lines. This uses the same trick discussed in the previous example.
INTEGER :: a, b, Smaller
READ(*,*) a, b
Smaller = a
IF (a > b) THEN
Smaller = b
END IF
Write(*,*) 'The smaller of ', a, ' and ', &
b, ' is ', Smaller
INTEGER :: Counter
A USEFUL TIP
The box trick can also be used with this IF-THEN-END IF form. Since there is no ELSE, you
can leave the lower part empty like the following:
LOGICAL IF
IF (logical-expression) one-statement
where one-statement is a executable statement which is not another IF, and logical-
expression is a logical expression. The execution of this logical IF statement goes as
follows:
Note that this logical IF does have its use although it looks not so powerful comparing with
IF-THEN-ELSE-END IF and IF-THEN-END IF.
EXAMPLES
• The following program segment computes the absolute value of X and saves the
result into variable Absolute_X. Recall that the absolute value of x is x if x is non-
negative; otherwise, the absolute value is -x. For example, the absolute value of 5 is
5 and the absolute value of -4 is 4=-(-4). Also note that the WRITE(*,*) statement
has been intentionally broken into two lines with the continuation line symbol &. The
trick is that the value of X is first saved to Absolute_X whose value is changed later
only if the value of X is less than zero.
REAL :: X, Absolute_X
X = .....
Absolute_X = X
IF (X < 0.0) Absolute_X = -X
WRITE(*,*) 'The absolute value of ', x, &
' is ', Absolute_X
• The following program segment reads in two integer values into a and b and finds
the smaller one into Smaller. Note that the WRITE(*,*) has also been broken into
two lines. This uses the same trick discussed in the previous example.
INTEGER :: a, b, Smaller
READ(*,*) a, b
Smaller = a
IF (a > b) Smaller = b
Write(*,*) 'The smaller of ', a, ' and ', &
b, ' is ', Smaller
INTEGER :: Counter
The following is wrong since the one-statement if a logical IF can not be another
IF statement.
INTEGER :: a, b, c
PROBLEM STATEMENT
if b*b-4*a*c is non-negative, the roots of the equation can be solved with the following
formulae:
Write a program to read in the coefficients a, b and c, and compute and display the roots. If the
discriminant b*b - 4*a*c is negative, the equation has complex root. Thus, this program should
solve the equation if the discriminant is non-negative and show a message otherwise.
SOLUTION
! ---------------------------------------------------
! Solve Ax^2 + Bx + C = 0 given B*B-4*A*C >= 0
! Now, we are able to detect complex roots.
! ---------------------------------------------------
PROGRAM QuadraticEquation
IMPLICIT NONE
REAL :: a, b, c
REAL :: d
REAL :: root1, root2
READ(*,*) a, b, c
WRITE(*,*) 'a = ', a
WRITE(*,*) 'b = ', b
WRITE(*,*) 'c = ', c
WRITE(*,*)
d = b*b - 4.0*a*c
IF (d >= 0.0) THEN ! is it solvable?
d = SQRT(d)
root1 = (-b + d)/(2.0*a) ! first root
root2 = (-b - d)/(2.0*a) ! second root
WRITE(*,*) 'Roots are ', root1, ' and ', root2
ELSE ! complex roots
WRITE(*,*) 'There is no real roots!'
WRITE(*,*) 'Discriminant = ', d
END IF
• If the input to the program consists of 1.0, 5.0 and 2.0, we have the following output.
Since the discriminant is b*b - 4.0*a*c = 5.0*5.0 - 4.0*1.0*2.0 = 17.0 > 0.0, the
THEN part is executed and the real roots are -0.438447237 and -4.561553.
a = 1.
b = 5.
c = 2.
Roots are -0.438447237 and -4.561553
• If the input to the program consists of 1.0, 2.0 and 5.0, we have the following output.
Since the discriminant is b*b - 4.0*a*c = 2.0*2.0 - 4.0*1.0*5.0 = -16.0 < 0.0, the
ELSE part is executed and a message of no real roots is displayed followed the value
of the discriminant.
a = 1.
b = 2.
c = 5.
DISCUSSION
Here is the box trick of this program. Note that information in different parts of the box do
not have to be very precise. As long as it can tell what to do, it would be sufficient.
PROBLEM STATEMENT
Two examination papers are written at the end of the course. The final mark is either the average
of the two papers, or the average of the two papers and the class record mark (all weighted
equally), whichever is the higher. The program should reads in the class record mark and the
marks of the papers, computes the average, and shows PASS (>= 50%) or FAIL (< 50%).
SOLUTION
! -------------------------------------------------------------
! Two examination papers are written at the end of the course.
! The final mark is either the average of the two papers, or
! the average of the two papers and the class record mark (all
! weighted equally), whichever is the higher. The program
! should reads in the class record mark and the marks of the
! papers, computes the average, and shows PASS (>= 50%) or
! FAIL (< 50%).
! -------------------------------------------------------------
PROGRAM FinalMark
IMPLICIT NONE
• If the input to class record mark, the mark of the first paper, and the mark of the
second paper are 40.0, 60.0 and 43.0, the average is (60.0 + 43.0)/2 = 51.5, which is
larger than the class record mark (40.0). Therefore, this student has a final mark 51.5
and receives a PASS status.
• If the input to class record mark, the mark of the first paper, and the mark of the
second paper are 60.0, 45.0 and 43.0, then the average is (45.0 + 43.0)/2 = 44.0,
which is less than the class record mark (60.0). Therefore, this student's new mark is
the average of his marks and the class record mark, (60.0 + 45.0 + 43.0)/3.0 =
49.33333. Since this new mark is less than 50.0, this student receives a FAIL status.
DISCUSSION
• The READ statement reads in values for ClassRecordMark, Mark1 and Mark2.
• The average of papers is computed and stored in Final
• If this final mark is less than or equal to the class record mark, a new final mark is
computed as the average of the two marks and the class record mark. Here, the IF-
THEN-END form is used. You can use the logical IF form; but, this line could be too
long. As mentioned earlier, the IF-THEN-END IF is preferred.
• The four WRITE(*,*) statements display the input and the computed final mark.
• Finally, the IF-THEN-ELSE-END IF determines if the final mark is a pass or a fail.
PROBLEM STATEMENT
Given a triangle with side lengths a, b and c, its area can be computed using the Heron's formula:
Write a program to read in the coefficients a, b and c, and compute the area of the triangle.
However, not any three numbers can make a triangle. There are two conditions. First, all side
lengths must be positive:
and second the sum of any two side lengths must be greater than the third side length:
In the program, these two conditions must be checked before computing the triangle area;
otherwise, square root computation will be in trouble.
SOLUTION
! ------------------------------------------------------
! Compute the area of a triangle using Heron's formula
! ------------------------------------------------------
PROGRAM HeronFormula
IMPLICIT NONE
READ(*,*) a, b, c
• If the input to the program consists of 3.0, 5.0 and 7.0, we have the following output.
Since the value of all input are positive and the sum of any two is larger than the
third (i.e., 3.0+5.0 > 7.0, 3.0+7.0+5.0 and 5.0+7.0>3.0), both conditions hold and
the program can compute the area of the triangle. The area is 6.49519062.
a = 3.
b = 5.
c = 7.
• If the input to the program consists of 3.0, 4.0 and 7.0, we have the following output.
Although all input values are positive, this is not a triangle since the sum of the first
side (3.0) and the second (4.0) is not grater than the third (8.0). The program
generates an error message.
3.0 4.0 8.0
a = 3.
b = 4.
c = 8.
• If the input to the program consists of -1.0, 3.0 and 5.0, we have the following output.
Since not all input values are positive, this is not a triangle.
a = -1.
b = 3.
c = 5.
DISCUSSION
• This program uses two LOGICAL variables, Cond_1 and Cond_2 to store the results
of the two conditions.
• The conditions are checked with the first two assignments.
• Since all side lengths must be greater than zero, operator .AND. are used to connect
a > 0.0, b > 0.0 and c > 0.0.
• Since the sum of any two side lengths must be greater than the third side length, all
three comparisons must be .TRUE. and operator .AND. is used.
• Since both conditions must be true in order to have a triangle, .AND. is also used in
the IF-THEN-ELSE-END IF statement.
• If both conditions are .TRUE., the THEN part is executed, where the value of s and
the area is computed and displayed.
• If one or both conditions is .FALSE., the input is not a triangle and an error message
is displayed.
• You can pull all six comparisons into a single logical expression. But, this expression
could be too long to be fit into a single line. While continuation line can be used, it
may not be readable. So, I prefer to have separate lines.
NESTED IF-THEN-ELSE-END IF
The THEN part and the ELSE part, if any, can contain one or more IF-THEN-ELSE-END IF
statement in one of the three forms. That is, when you feel it is necessary, you can use as many
IF-THEN-ELSE-END IF statements in the THEN part and the ELSE part as you want.
However, please note that any such IF-THEN-ELSE-END IF must be fully contained in the
THEN part or the ELSE part. If you follow the box trick, this requirement is automatically
satisfied. The following is an example:
IF (logical-expression) THEN
statements
IF (logical-expression) THEN
statements
ELSE
statements
END IF
statements
ELSE
statements
IF (logical-expression) THEN
statements
END IF
statements
END IF
EXAMPLES
• Suppose we need a program segment to read a number x and display its sign. More
precisely, if x is positive, a + is displayed; if x is negative, a - is displayed; otherwise,
a 0 is displayed. With an IF-THEN-ELSE-END IF statement, we have a two-way
decision (i.e., true or false). What we need is a tree-way decision and some trick is
required. In this case, the box trick can be very helpful.
display +
x>
0 one down (i.e., +) two to go (i.e.,
- and 0)
In the lower part, no decision can been reached. What we want to know is finding out is x
is zero or negative (x cannot be positive here since it has been ruled out in the upper
part). To determine whether a - or a 0 should be displayed, one more decision is required:
display -
x<
0 display
0)
Since this is the work for the lower rectangle, let us put it there yielding the following:
display +
display
x>
-
0 x <
0
display
0
IF (x > 0) THEN
WRITE(*,*) '+'
ELSE
IF (x < 0) THEN
WRITE(*,*) '-'
ELSE
WRITE(*,*) '0'
END IF
END IF
• Given a x, we want to display the value of -x if x < 0, the value of x*x if x is in the
range of 0 and 1 inclusive, and the value of 2*x if x is greater than 1.
Obviously, this problem cannot be solved with a two-way IF and the box trick becomes
useful. Let us start with x<0.
display -x
x<
0 here we have x
>= 0
For the x >= 0 part, x may be in the range of 0 and 1; if not, x must be greater than 1
since x cannot be less than 0. Therefore, we have the following box for the case of x >=
0:
Inserting this box into the previous one yields the following final result:
x < display -x
display
x*x
x <=
0
1
display
2*x
IF (x < 0) THEN
WRITE(*,*) -x
ELSE
IF (x <= 1) THEN
WRITE(*,*) x*x
ELSE
WRITE(*,*) 2*x
END IF
END IF
• Given three numbers a, b and c, we want to find out the smallest one.
There are many solutions to this problem; but, we shall use the box trick again. Let us
pick two numbers, say a and b. Thus, we get the following:
Now we know a possible smallest number. To find the real smallest one, this "possible"
number must be compared against c. If the possible one is a (the upper part), we need to
do the following:
a is the smallest
a<
c since c <= a and b <= a, c is
the smallest
Let us turn to the lower part, where b has the potential to be the smallest. Comparing with
c yields:
b is the smallest
b<
c since c <= b and b <= a, c is
the smallest
Inserting the above two boxes into the first one yields the following complete solution:
the smallest
is a
a <
c
the smallest
is c
a<
b
the smallest
is b
b <
c
the smallest
is c
IF (a < b) THEN
IF (a < c) THEN
Result = a
ELSE
Result = c
END IF
ELSE
IF (b < c) THEN
Result = b
ELSE
Result = c
END IF
END IF
WRITE(*,*) 'The smallest is ', Result
The above code segment uses variable Result to hold the smallest value.
IF-THEN-ELSE IF-END IF
IF (logical-expression-1) THEN
statements-1
ELSE IF (logical-expression-2) THEN
statements-2
ELSE IF (logical-expression-3) THEN
statement-3
ELSE IF (.....) THEN
...........
ELSE
statements-ELSE
END IF
Fortran evaluates logical-expression-1 and if the result is .TRUE., statements-1 is executed
followed by the statement after END IF. If logical-expression-1 is .FALSE., Fortran evaluates
logical-expression-2 and executes statements-2 and so on. In general, if logical-expression-n
is .TRUE., statements-n is executed followed by the statement after END IF; otherwise,
Fortran continues to evaluate the next logical expression.
If all logical expressions are .FALSE. and if ELSE is there, Fortran executes the statements-
ELSE; otherwise, Fortran executes the statement after the END IF.
Note that the statements in the THEN section, ELSE IF section, and ELSE section can be
another IF statement.
EXAMPLES
• Suppose we need a program segment to read a number x and display its sign. More
precisely, if x is positive, a + is displayed; if x is negative, a - is displayed; otherwise,
a 0 is displayed. Here is a possible solution using IF-THEN-ELSE IF-END IF:
IF (x > 0) THEN
WRITE(*,*) '+'
ELSE IF (x == 0) THEN
WRITE(*,*) '0'
ELSE
WRITE(*,*) '-'
END IF
• Given a x, we want to display the value of -x if x < 0, the value of x*x if x is in the
range of 0 and 1 inclusive, and the value of 2*x if x is greater than 1.
IF (x < 0) THEN
WRITE(*,*) -x
ELSE IF (x <= 1) THEN
WRITE(*,*) x*x
ELSE
WRITE(*,*) 2*x
END IF
INTEGER :: x
CHARACTER(LEN=1) :: Grade
First, if x is less than 50, 'F' is assigned to Grade. If x is greater than or equal to 50,
the execution continue with the first ELSE IF where x < 60 is tested. If it is .TRUE.,
'D' is assigned to Grade. Note that one can reach the test of x < 60 simply because
the test x < 50 is .FALSE.. Therefore, when reaches x < 60, we are sure that x >=
50 must hold and as a result, Grade receives 'D' if x is greater than or equal to 50
and is less than 60.
By the same token, we know that if x is greater than or equal to 60 and is less than 70,
Grade receives 'C'. If x is greater than or equal to 70 and is less than 80, Grade receives
'B'. Finally, if x is greater than or equal to 80, Grade receives 'A'.
The first and second examples show that IF-THEN-ELSE IF-END IF can save some space
and at the same time make a program more readable. Compare these two solutions with
those using nest IF.
Note also that not all nested IF can be converted to the IF-THEN-ELSE IF-ELSE-END-IF
form. For example, the example of determining the smallest of three numbers cannot be
converted immediately. In general, if all tests (i.e., logical expressions) are mutually exclusive,
then the chance to have a successful conversion is high. Otherwise, rewriting some parts or
combining logical expression can be helpful. Here is one more example:
Let us reconsider the problem of finding the smallest of three given numbers. We know that if a
is the smallest, then it must be smaller than the other two. Moreover, the condition for a number
being the smallest is mutually exclusive. Thus, we have a successful conversion as follows:
PROBLEM STATEMENT
Write a program to read in the coefficients a, b and c, and solve the equation. Note that a
quadratic equation has repeated root if b*b-4.0*a*c is equal to zero. This program should
distinguish repeated roots from distinct roots.
SOLUTION
! ---------------------------------------------------
! Solve Ax^2 + Bx + C = 0 given B*B-4*A*C >= 0
! Now, we are able to detect complex roots and
! repeated roots.
! ---------------------------------------------------
PROGRAM QuadraticEquation
IMPLICIT NONE
REAL :: a, b, c
REAL :: d
REAL :: root1, root2
READ(*,*) a, b, c
WRITE(*,*) 'a = ', a
WRITE(*,*) 'b = ', b
WRITE(*,*) 'c = ', c
WRITE(*,*)
d = b*b - 4.0*a*c
IF (d > 0.0) THEN ! distinct roots?
d = SQRT(d)
root1 = (-b + d)/(2.0*a) ! first root
root2 = (-b - d)/(2.0*a) ! second root
WRITE(*,*) 'Roots are ', root1, ' and ', root2
ELSE
IF (d == 0.0) THEN ! repeated roots?
WRITE(*,*) 'The repeated root is ', -b/(2.0*a)
ELSE ! complex roots
WRITE(*,*) 'There is no real roots!'
WRITE(*,*) 'Discriminant = ', d
END IF
END IF
• If the input to the program consists of 1.0, 5.0 and 2.0, we have the following output.
Since the discriminant is b*b - 4.0*a*c = 5.0*5.0 - 4.0*1.0*2.0 = 17.0 > 0.0, the
THEN part is executed and the real roots are -0.438447237 and -4.561553.
a = 1.
b = 5.
c = 2.
• If the input to the program consists of 1.0, -10.0 and 25.0, we have the following
output. Since the discriminant is b*b - 4.0*a*c = (-10.0)*(-10.0) - 4.0*1.0*25.0 =
0.0, the ELSE part is executed. Since there is a nested IF-THEN-ELSE-END IF in the
ELSE, d = 0.0 is tested and therefore yields a repeated root 5.
a = 1.
b = -10.
c = 25.
• If the input to the program consists of 1.0, 2.0 and 5.0, we have the following output.
Since the discriminant is b*b - 4.0*a*c = 2.0*2.0 - 4.0*1.0*5.0 = -16.0 < 0.0, the
ELSE part is executed. Since d < 0.0, the ELSE part of the inner IF-THEN-ELSE-
END IF is executed and a message of no real roots is displayed followed by the value
of the discriminant.
a = 1.
b = 2.
c = 5.
DISCUSSION
Here is the box trick of this program.
computes the real roots
b*b - 4.0*a*c
> 0.0 repeated root or no real
root
The lower part is not complete yet since we do not know if the equation has a repeated root.
Therefore, one more test is required:
Inserting this back to the original yields the following final result:
The following is an equivalent program that uses ELSE-IF construct rather than nested IF:
! ---------------------------------------------------
! Solve Ax^2 + Bx + C = 0 given B*B-4*A*C >= 0
! Now, we are able to detect complex roots and
! repeated roots.
! ---------------------------------------------------
PROGRAM QuadraticEquation
IMPLICIT NONE
REAL :: a, b, c
REAL :: d
REAL :: root1, root2
READ(*,*) a, b, c
WRITE(*,*) 'a = ', a
WRITE(*,*) 'b = ', b
WRITE(*,*) 'c = ', c
WRITE(*,*)
! compute the discriminant d
d = b*b - 4.0*a*c
IF (d > 0.0) THEN ! distinct roots?
d = SQRT(d)
root1 = (-b + d)/(2.0*a) ! first root
root2 = (-b - d)/(2.0*a) ! second root
WRITE(*,*) 'Roots are ', root1, ' and ', root2
ELSE IF (d == 0.0) THEN ! repeated roots?
WRITE(*,*) 'The repeated root is ', -b/(2.0*a)
ELSE ! complex roots
WRITE(*,*) 'There is no real roots!'
WRITE(*,*) 'Discriminant = ', d
END IF
>
computes the real roots
>
no real root
PROBLEM STATEMENT
if b*b-4*a*c is non-negative, the roots of the equation can be solved with the following
formulae:
Write a program to read in the coefficients a, b and c, and solve the equation. Note that a
quadratic equation has repeated root if b*b-4.0*a*c is equal to zero.
However, if a is zero, the equation becomes a linear one whose only solution is -c/b if b is not
zero. Otherwise, if b is zero, two cases are possible. First, if c is also zero, any number can be a
solution because all three coefficients are zero. Otherwise, the equation c = 0 cannot have any
solution.
SOLUTION
! ---------------------------------------------------
! Solve Ax^2 + Bx + C = 0 given B*B-4*A*C >= 0
! Now, we are able to detect the following:
! (1) unsolvable equation
! (2) linear equation
! (3) quadratic equation
! (a) distinct real roots
! (b) repeated root
! (c) no real roots
! ---------------------------------------------------
PROGRAM QuadraticEquation
IMPLICIT NONE
REAL :: a, b, c
REAL :: d
REAL :: root1, root2
READ(*,*) a, b, c
WRITE(*,*) 'a = ', a
WRITE(*,*) 'b = ', b
WRITE(*,*) 'c = ', c
WRITE(*,*)
• If the input to the program consists of 0.0, 1.0 and 5.0, we have the following output.
Since a is zero, this could be a linear equation. Since b=1.0, it is a linear equation
1.0*x + 5.0 = 0.0 with the only root -5.0/2.0=-5.0.
a = 0.E+0
b = 1.
c = 5.
• If the input to the program consists of 0.0, 0.0 and 0.0, we have the following output.
Since all coefficients are zero, any number is a root.
a = 0.E+0
b = 0.E+0
c = 0.E+0
• If the input to the program consists of 0.0, 0.0 and 4.0, we have the following output.
Since the equation becomes 4.0 = 0.0, which is impossible. Therefore, this is not a
solvable equation.
a = 0.E+0
b = 0.E+0
c = 4.
Unsolvable equation
DISCUSSION
Here is the box trick of this program. It is more complex than all previous versions of
quadratic equation solvers.
it could be a linear
a = equation
0
a quadratic equation
Since we have learned to do the quadratic part, we shall do the linear equation part first. To be a
linear equation, b cannot be zero and this has to be addressed in the upper rectangle:
a quadratic equation
a quadratic equation
To complete the bottom rectangle, let us take the box from previous example. The final result is:
PROBLEM STATEMENT
Give three integers, display them in ascending order. For example, if the input is 2, 3 and 1, this
program should display 1, 2 and 3.
SOLUTION
! -------------------------------------------------------
! This program reads in three INTEGERs and displays them
! in ascending order.
! -------------------------------------------------------
PROGRAM Order
IMPLICIT NONE
INTEGER :: a, b, c
READ(*,*) a, b, c
DISCUSSION
This is a good example for using the box trick. The main idea is that if we know the smallest
number, then one comparison between the remaining two would give the second smallest
and the largest number. Finding the smallest of three numbers has been discussed in
nested IF.
a may be the
smallest
a<
b
b may be the
smallest
For the upper rectangle, we need to know if a is less than c, while for the lower rectangle we
need to know if b is less than c:
For the top rectangle, we need one more comparison b < c and for the rectangle on the third row
we need a < c. The following is our final result:
The above can be simplified a little if you use LOGICAL operators as discussed in nested IF.
Here is the box diagram:
a < b < c
here
a < b and a b <
<c c
a < b <= c
here
b < a < c
here
b < a and b a <
<c c
b < c <= a
here
c < a < b
here
c < a and c a <
<b b
c < b <= a
here
! -------------------------------------------------------
! This program reads in three INTEGERs and displays them
! in ascending order.
! -------------------------------------------------------
PROGRAM Order
IMPLICIT NONE
INTEGER :: a, b, c
READ(*,*) a, b, c
IF (a <= b .AND. a <= c) THEN ! a the smallest
IF (b <= c) THEN ! a <= b <= c
WRITE(*,*) a, b, c
ELSE ! a <= c <= b
WRITE(*,*) a, c, b
END IF
ELSE IF (b <= a .AND. b <= c) THEN ! b the smallest
IF (a <= c) THEN ! b <= a <= c
WRITE(*,*) b, a, c
ELSE ! b <= c <= a
WRITE(*,*) b, c, a
END IF
ELSE ! c the smallest
IF (a <= b) THEN ! c <= a <= b
WRITE(*,*) c, a, b
ELSE ! c <= b <= a
WRITE(*,*) c, b, a
END IF
END IF
Fortran has one more selective execution statement, SELECT CASE, and could be very handy
if it is used properly. The SELECT CASE statement is also usually referred to as the CASE
statement. The following is its syntactic form:
value
value-1 : value-2
value-1 :
: value-2
where value, value-1 and value-2 are constants or alias defined by PARAMETER. The type
of these constants must be identical to that of the selector.
EXAMPLES
INTEGER :: Class
• In the following, the value of CHARACTER variable Title is used as a selector. If its
value is "DrMD" (resp., "PhD", "MS" and "BS"), then INTEGER variables DrMD
(resp., PhD, MS and BS) is increased by 1. Otherwise, Others is increased.
CHARACTER(LEN=4) :: Title
INTEGER :: DrMD = 0, PhD = 0, MS = 0, BS = 0, Others = 0
• The follow example does not use CASE DEFAULT since the label lists have already
covered all possibilities. If the value of Number is less than or equal to -1 (:-1), -1 is
stored into Sign. If the value of Number is zero, 0 is stored into Sign. If the value of
Number is greater than or equal to 1, 1 is stored into Sign.
• If the value of c is one of the first ten letters (in lower case), 'One of the first ten
letters' is displayed; if the value of c is one of l, m, n, o, p, u, v, w, x, y, 'One of l,
m, n, o, p, u, v, w, x, y' is displayed; if the value of c is one of z, q, r, s, t, 'One of
z, q, r, s, t' is displayed; and if the value of c is none of the above, 'Other
characters, which may not be letters' is displayed. In the last case, the value of c
could be one of these lower case letters not listed, an upper case letters, a digit, an
operator, or any other character. So, if you only want to handle lower case letters,
this program is incorrect.
CHARACTER(LEN=1) :: c
SELECT CASE (c)
CASE ('a' : 'j')
WRITE(*,*) 'One of the first ten letters'
CASE ('l' : 'p', 'u' : 'y')
WRITE(*,*) 'One of l, m, n, o, p, u, v, w, x, y'
CASE ('z', 'q' : 't')
WRITE(*,*) 'One of z, q, r, s, t'
CASE DEFAULT
WRITE(*,*) 'Other characters, which may not be letters'
END SELECT
• The following program uses the value of Number to determine the value of Range.
Rang
Number Why?
e
CASE ( : -10,
<= -10 1
10 : )
CASE (-5:-3,
-5, -4, -3 2
6:9)
-2, -1, 0,
3 CASE (-2:2)
1, 2
3 4 CASE (3, 5)
4 5 CASE (4)
5 4 CASE (3, 5)
CASE (-5:-3,
6, 7, 8, 9 2
6:9)
CASE ( : -10,
>= 10 1
10 : )
PROBLEM STATEMENT
At the end of a quarter, the average of three marks must be computed. Then, this average is
rounded and used to determine the corresponding letter grade. The letter grades are computed as
follows:
Grad
Range
e
>= 90 A
< 90 and
AB
>= 85
< 85 and
B
>= 80
< 80 and
BC
>= 75
< 75 and
C
>= 70
< 70 and
CD
>= 65
< 65 and
D
>= 60
< 60 F
Write a program to read three marks, compute its average, round the average and use it to
determine the corresponding letter grade.
SOLUTION
! ----------------------------------------------------------
! This program reads three marks, computes their average
! and determines the corresponding letter grade with
! the following table:
!
! A : average >= 90
! AB : 85 <= average < 90
! B : 80 <= average < 84
! BC : 75 <= average < 79
! C : 70 <= average < 74
! CD : 65 <= average < 69
! D : 60 <= average < 64
! F : average < 60
!
! where 'average' is the rounded average of the three
! marks. More precisely, if the average is 78.6, then it
! becomes 79 after rounding; or, if the average is 78.4,
! it becomes 78 after truncating.
! ----------------------------------------------------------
PROGRAM LetterGrade
IMPLICIT NONE
• The following output is generated from input 97.0, 90.0 and 94.0. The average is
93.66666641. The result after rounding is 94 and hence the letter grade is an A.
• The following output is generated from input 92.0, 85.0 and 83.0. The average is
86.6666641. The result after rounding is 87 and hence the letter grade is an AB.
• The following output is generated from input 75.0, 60.0 and 45.0. The average is
60.0. The result after rounding is 60 and hence the letter grade is an D.
DISCUSSION
This is an easy example and only one place requires further explanation. The concept of
rounding is converting a real number to its nearest integer. Therefore, after rounding, 4.5
and 4.4 become 5 and 4, respectively. Moreover, after rounding, -4.5 and -4.4 become -5
and -4, respectively. The Fortran intrinsic function for rounding is NINT(), which was
discussed in Fortran intrinsic functions.
In the program, REAL variable Average holds the average of the three input marks. To round
the average value to be used in the SELECT CASE statement, NINT(Average) is used. Other
parts are obvious.
PROGRAMMING EXAMPLE 2: CHARACTER TESTING
PROBLEM STATEMENT
This is an extension of an example discussed in SELECT CASE statement. This program reads
in a character and determines if it is a vowel, a consonant, a digit, one of the four arithmetic
operators, a space, or something else (i.e., %, $, @, etc).
SOLUTION
! ------------------------------------------------------------
! This program reads in a single character and determines if
! it is a vowel, a consonant, a digit, one of the four
! arithmetic operators (+, -, * and /), a space, or something
! else. You can do it with IF-THEN-ELSE-END IF statement; but
! SELECT CASE statement provides a cleaner solution.
!
! For character input, you could use the quote characters like
! 'G'
! Or, just type the character. In this case, the first
! character you type will be read.
! ------------------------------------------------------------
PROGRAM CharacterTesting
IMPLICIT NONE
CHARACTER(LEN=1) :: Input
READ(*,*) Input
• If the input character is none of the above, say &, the program should report it is
something else.
DISCUSSION
To be a vowel or a consonant, the input character must be a lower or upper case letter. So,
the first CASE of the outer SELECT CASE singles out all letters. Within the first CASE,
another SELECT CASE is used to separate vowels from consonants. Since a letter is either a
vowel or a consonant, we use the shorter list (i.e., vowels) in the CASE label and let CASE
DEFAULT deal with the longer list of consonants.
AKHIR PERTEMUAN 2
REPETITIVE EXECUTION
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
WRITE(*,*) 'This program computes the factorial of'
WRITE(*,*) 'a non-negative integer'
WRITE(*,*)
WRITE(*,*) 'What is N in N! --> '
READ(*,*) N
WRITE(*,*)
• 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
INTEGER :: i
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
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
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:
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.
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
3 is 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
3 1 6 8 10
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
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.
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
X = X + Step
END DO
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
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
WRITE(*,*)
WRITE(*,*) 'There are ', Count, ' primes in the range of 2 and ', Range
• 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
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.
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.
Akhir Pertemuan 3
Designing Functions
Functions Examples
Common Problems
Using Functions
Argument Association
Computing Cubes
What is a Module?
Interface Blocks
DESIGNING FUNCTIONS
SYNTAX
In addition to intrinsic functions, Fortran allows you to design your own functions. A Fortran
function, or more precisely, a Fortran function subprogram, has the following syntax:
• The first line of a function starts with the keyword FUNCTION. Before FUNCTION,
the type gives the type of the function value (i.e., INTEGER, REAL, LOGICAL and
CHARACTER) and after FUNCTION is the name you assign to that function.
• Following the function-name, there is a pair of parenthesis in which a number of
arguments arg1, arg2, ..., argn are separated with commas. These arguments are
referred to as formal arguments. Formal arguments must be variable names and
cannot be expressions. Here are a examples:
1. The following is a function called Factorial. It takes only one formal argument
n and returns an INTEGER as its function value.
• INTEGER FUNCTION Factorial(n)
1. The following is a function called TestSomething. It takes three formal
arguments a, b and c, and returns a LOGICAL value (i.e., .TRUE. or .FALSE.)
as its function value.
• LOGICAL FUNCTION TestSomething(a, b, c)
• A function must be ended with END FUNCTION followed by the name of that
function.
• Between FUNCTION and END FUNCTION, there are the IMPLICIT NONE,
specification part, execution part and subprogram part. These are exactly identical to
that of a PROGRAM.
SEMANTICS
The meaning of a function is very simple:
• A function is a self-contained unit that receives some "input" from the outside world
via its formal arguments, does some computations, and then returns the result with
the name of the function.
• Thus, since the function returns its result via the name of the function, somewhere in
the function there must exist one or more assignment statements like the following:
• function-name = expression
where the result of expression is stored to the name of the function.
However, the name of the function cannot appear in the right-hand side of any
expression. That is, the name of the function, used as a variable name, can only appear in
the left-hand side of an expression. This is an artificial restriction in this course only.
• A function receives its input values from formal arguments, does computations, and
saves the result in its name. When the control of execution reaches END FUNCTION,
the value stored in the name of the function is returned as the function value.
• To tell the function about the types of its formal arguments, all arguments must be
declared with a new attribute INTENT(IN). The meaning of INTENT(IN) indicates
that the function will only take the value from the formal argument and must not
change its content.
• Any statements that can be used in PROGRAM can also be used in a FUNCTION.
FUNCTIONS EXAMPLES
• The following function has a name Sum and three formal arguments a, b and c. It
returns an INTEGER function value. The INTEGER, INTENT(IN) part indicates that
the function takes its input value from its three formal argument. Then, the function
uses the value of these formal arguments to compute the sum and stores in Sum,
the name of the function. Since the next statement is END FUNCTION, the function
returns the value stored in Sum.
INTEGER, INTENT(IN) :: a, b, c
Sum = a + b + c
END FUNCTION Sum
If the value supplied to a, b and c are 3, 5, and -2, respectively, Sum will receive 6
(=3+5+(-2)) and the function returns 6.
• The following function has a name Positive with a REAL formal argument. If the
argument is positive, the function returns .TRUE.; otherwise, the function returns
.FALSE.
REAL, INTENT(IN) :: a
The above function can be made much shorter by using LOGICAL assignment. In the
following, if a > 0.0 is true, .TRUE. is stored to Positive; otherwise, Positive
receives .FALSE.
REAL, INTENT(IN) :: a
• The following function, LargerRoot, takes three REAL formal arguments and returns
a REAL function value. It returns the larger root of a quadratic equation ax2 + bx + c
= 0.
REAL, INTENT(IN) :: a
REAL, INTENT(IN) :: b
REAL, INTENT(IN) :: c
REAL :: d, r1, r2
d = SQRT(b*b - 4.0*a*c)
r1= (-b + d) / (2.0*a)
r2= (-b - d) / (2.0*a)
IF(r1 >= r2) THEN
LargerRoot = r1
ELSE
LargerRoot = r2
END IF
END FUNCTION LargerRoot
The above example shows that you can declare other variables such as d, r1 and r2
if they are needed.
• The following function, Factorial(), has only one INTEGER formal argument n >= 0,
and computes and returns the factorial of n, n!.
INTEGER, INTENT(IN) :: n
INTEGER :: i, Ans
Ans = 1
DO i = 1, n
Ans = Ans * i
END DO
Factorial = Ans
END FUNCTION
Note that the function name Factorial is not used in any computation. Instead, a
new INTEGER variable is used for computing n!. The final value of Ans is stored to
Factorial before leaving the function.
INTEGER, INTENT(IN) :: n
INTEGER :: i
Factorial = 1
DO i = 1, n
Factorial = Factorial * i
END DO
END FUNCTION
then there is a mistake although the above program looks normal. The reason is that
the function name cannot appear in the right-hand side in any expression of that
function.
• The following function GetNumber() does not have any formal arguments and
returns an INTEGER function value. This function has a DO-loop which keeps asking
the user to input a positive number. The input is read into the function name. If this
value is positive, then EXIT and the function returns the value in GetNumber.
Otherwise, the loop goes back and asks the user again for a new input value.
DO
WRITE(*,*) 'A positive real number --> '
READ(*,*) GetNumber
IF (GetNumber > 0.0) EXIT
WRITE(*,*) 'ERROR. Please try again.'
END DO
WRITE(*,*)
END FUNCTION GetNumber
COMMON PROBLEMS
FUNCTION DoSomething(a, b)
IMPLICIT NONE
INTEGER, INTENT(IN) :: a, b
If there is no type, you will not be able to determine if the returned value is an
INTEGER, a REAL or something else.
Forget INTENT(IN).
INTEGER :: a, b
Actually, this is not an error. But, without INTENT(IN), our Fortran compiler will not
be able to check many potential errors for you.
INTEGER, INTENT(IN) :: a, b
IF (a > b) THEN
a = a - b
ELSE
a = a + b
END IF
DoSomthing = SQRT(a*a + b*b)
END FUNCTION DoSomthing
Since formal argument a is declared with INTENT(IN), its value cannot be changed.
INTEGER, INTENT(IN) :: a, b
INTEGER :: c
c = SQRT(a*a + b*b)
END FUNCTION DoSomthing
When the execution of this function reaches END FUNCTION, it returns the value
stored in DoSomething. However, in the above, since there is no value ever stored
in DoSmething, the returned value could be anything (i.e., a garbage value).
Function name is used in the right-hand side of an expression.
INTEGER, INTENT(IN) :: a, b
In the above, function name DoSomething appears in the right-hand side of the
second expression. This is a mistake. Only a special type of functions, RECURSIVE
functions, could have their names in the right-hand side of expressions.
• Only the most recent value stored in the function name will be returned..
INTEGER, INTENT(IN) :: a, b
In the above, the value of SQRT(a*a-b*b) rather than the value of a*a + b*b is
returned. In fact, this is obvious. Since the name of a function can be considered as a
special variable name, the second assignment overwrites the previous value.
USING FUNCTIONS
The way of using a user-defined function is exactly identical to that of using Fortran intrinsic
functions. One can use a function in an expression and in a WRITE. Suppose we have the
following function:
REAL, INTENT(IN) :: x, y, z
Average = (x + y + z) / 3.0
END FUNCTION Average
This function takes three REAL formal arguments and returns their average.
To use this function, one needs to supply values to the formal arguments. For example, one could
write the following:
The first line has more actual arguments than the number of formal arguments, and
the second line has less actual arguments than the number of formal arguments.
The type of the corresponding actual and formal arguments must be identical.
In the above example, the first actual argument is an INTEGER which doe not match
with the type of the first formal argument. Thus, it is incorrect.
In the above, the first line shows the use of constants as actual arguments. The
second line uses variables, while the third uses expression. In the third line, the result
of evaluating a+b, b*c and (b+c)/a will be supplied to the three formal arguments of
function Average().
ARGUMENT ASSOCIATION
When using a function, the values of actual arguments are passed to their corresponding formal
arguments. There are some important rules:
EXAMPLE
We shall use the following function to illustrate the above rules. Function Small() takes
three formal arguments x, y and z and returns the value of the smallest.
In the first WRITE, all three arguments are variable and their values are sent to the
corresponding formal argument. Therefore, x, y and z in function Small() receives 10, 5 and 13,
respectively. The following diagram illustrate this association:
In the second WRITE, the first and second arguments are expression a+b, b+c. Thus, they are
evaluated yielding 15 and 18. These two values are saved in two temporary locations and passed
to function Small() along with variable c. Thus, x, y and z receive 15, 18 and 13 respectively.
This is illustrated as follows. In the figure, squares drawn with dotted lines are temperary
locations that are created for passing the values of arguments.
In the third WRITE, since all actual arguments are constants, their values are "evaluated" to
temporary locations and then sent to x, y and z.
In the fourth WRITE, since all three actual arguments are expressions, they are evaluated and
stored in temporary locations. Then, these values are passed to x, y and z.
Note that while the formal arguments of function Small() receive the same values using the
first and the fourth lines, the argument associations are totally different. The first line has
the values in variables passed directly and the the fourth line evaluates the expressions into
temporary locations whose values are passed. This way of argument association does not
have impact on functions (since you must use INTENT(IN)), it will play an important role
in subroutine subprograms.
Long time ago, we mentioned the structure of a Fortran program. From there, we know that the
last part of a program is subprogram part. This is the place for us to put the functions. Here is the
syntax:
PROGRAM program-name
IMPLICIT NONE
[specification part]
[execution part]
CONTAINS
[your functions]
END PROGRAM program-name
In the above, following all executable statements, there is the keyword CONTAINS, followed
by all of your functions, followed by END PROGRAM.
From now on, the program is usually referred to as the main program or the main program
unit. A program always starts its execution with the first statement of the main program. When a
function is required, the control of execution is transfered into the corresponding function until
the function completes its task and returns a function values. Then, the main program continues
its execution and uses the returned function value for further computation.
EXAMPLES
THE FOLLOWING COMPLETE PROGRAM "CONTAINS " ONE FUNCTION , AVERAGE(). THE EXECUTION PART
CONSISTS OF THREE STATEMENTS , A
READ, AN ASSIGNMENT AND A WRITE. THESE THREE
STATEMENTS MUST BE PLACED BEFORE THE KEYWORD CONTAINS. N OTE ALSO THAT END
PROGRAM MUST BE THE LAST LINE OF YOUR PROGRAM.
PROGRAM Avg
IMPLICIT NONE
REAL :: a, b, c, Mean
READ(*,*) a, b, c
Mean = Average(a, b, c)
WRITE(*,*) a, b, c, Mean
CONTAINS
REAL FUNCTION Average(a, b, c)
IMPLICIT NONE
REAL, INTENT(IN) :: a, b, c
Average = (a + b + c) / 3.0
END FUNCTION Average
END PROGRAM Avg
THE FOLLOWING PROGRAM "CONTAINS " TWO FUNCTIONS LARGE() AND GEOMEAN(). THE ORDER OF
THESE FUNCTIONS ARE UNIMPORTANT .
PROGRAM TwoFunctions
IMPLICIT NONE
INTEGER :: a, b, BiggerOne
REAL :: GeometricMean
READ(*,*) a, b
BiggerOne = Large(a,b)
GeometricMean = GeoMean(a,b)
WRITE(*,*) 'Input = ', a, b
WRITE(*,*) 'Larger one = ', BiggerOne
WRITE(*,*) 'Geometric Mean = ', GeometricMean
CONTAINS
INTEGER FUNCTION Large(a, b)
IMPLICIT NONE
INTEGER, INTENT(IN) :: a, b
IF (a >= b) THEN
Large = a
ELSE
Large = b
END IF
END FUNCTION Large
In the following example, the main program "contains" an internal function InternalFunction(),
which in turn contains another internal function Funct(). This is incorrect, since an internal
function cannot contain another internal function. In other words, the internal functions of a main
program must be on the same level.
PROGRAM Wrong
IMPLICIT NONE
.........
CONTAINS
INTEGER FUNCTION InternalFunction(.....)
IMPLICIT NONE
........
CONTAINS
REAL FUNCTION Funct(.....)
IMPLICIT NONE
........
END FUNCTION Funct
END FUNCTION InternalFunction
END PROGRAM Wrong
Please continue with the next important topic about scope rules.
SCOPE RULES
Since a main program could contain many functions and in fact a function can contain other
functions (i.e., nested functions), one may ask the following questions:
The scope rules answer these questions. In fact, scope rules tell us if an entity (i.e.,
variable, parameter and function) is "visible" or accessible at certain places. Thus, places
where an entity can be accessed or visible is referred to the scope of that entity.
Therefore, in the following, the scope of parameter PI and variables m and n is the main
program, the scope of formal argument k and REAL variables f and g is function Funct1(), and
the scope of formal arguments u and v is function Funct2().
PROGRAM Scope_1
IMPLICIT NONE
REAL, PARAMETER :: PI = 3.1415926
INTEGER :: m, n
...................
CONTAINS
INTEGER FUNCTION Funct1(k)
IMPLICIT NONE
INTEGER, INTENT(IN) :: k
REAL :: f, g
..........
END FUNCTION Funct1
LOCAL ENTITIES
Due to the above discussion, the entities declared in a function or in the main program are
said local to that function or the main program. Thus, k, f and g are local to function
Funct1(), u and v are local to function Funct2(), and PI, m and n are local to the main
program.
GLOBAL ENTITIES
Given a function f(), entities that are declared in all containing functions or the main
program are said global to f(). In the above example, since variables m and n are declared
in the main program, they are global to Funct1() and function Funct2(). However,
variables f and g are not global to function Funct2(), since Funct1() does not contain
Funct2(). Similarly, formal arguments u and v are not global to function Funct1().
Continue with the above example, since m and n are global to both functions Funct1() and
Funct2(), they can be used in these two functions.
PROGRAM Scope_2
IMPLICIT NONE
INTEGER :: a = 1, b = 2, c = 3
WRITE(*,*) Add(a)
c = 4
WRITE(*,*) Add(a)
WRITE(*,*) Mul(b,c)
CONTAINS
INTEGER FUNCTION Add(q)
IMPLICIT NONE
INTEGER, INTENT(IN) :: q
Add = q + c
END FUNCTION Add
In the above program, variables a, b and c are global to both functions Add() and Mul().
Therefore, since variable c used in function Add() is global to Add(), expression q + c
means computing the sum of the value of the formal argument q and the value of global
variable c. Therefore, the first WRITE produces 4 (= 1 + 3). Before the second WRITE, the
value of c is changed to 4 in the main program. Hence, the second WRITE produces 5 (= 1
+ 4). The third WRITE produces 8 (= 2 * 4).
Thus, the first two WRITEs produce different results even though their actual arguments are the
same! This is usually refereed to as a side effect. Therefore, if it is possible, avoid using global
variables in internal functions.
Let us continue with the above example. To remove side effect, one could add one more
argument to function Add() for passing the value of c.
PROGRAM Scope_2
IMPLICIT NONE
INTEGER :: a = 1, b = 2, c = 3
WRITE(*,*) Add(a, c)
c = 4
WRITE(*,*) Add(a, c)
WRITE(*,*) Mul(b,c)
CONTAINS
INTEGER FUNCTION Add(q, h)
IMPLICIT NONE
INTEGER, INTENT(IN) :: q, h
Add = q + h
END FUNCTION Add
PROGRAM Scope_3
IMPLICIT NONE
INTEGER :: i, Max = 5
DO i = 1, Max
Write(*,*) Sum(i)
END DO
CONTAINS
Programming Examples:
COMPUTING CUBES
PROBLEM STATEMENT
Write a program to compute the cubes of 1, 2, 3, ..., 10 in both INTEGER and REAL types. It is
required to write a function intCube() for computing the cube of an integer and a function
realCube() for computing the cube of a real.
SOLUTION
! -----------------------------------------------------
! This program display the cubes of INTEGERs and
! REALs. The cubes are computed with two functions:
! intCube() and realCube().
! -----------------------------------------------------
PROGRAM Cubes
IMPLICIT NONE
INTEGER, PARAMETER :: Iterations = 10
INTEGER :: i
REAL :: x
DO i = 1, Iterations
x = i
WRITE(*,*) i, x, intCube(i), realCube(x)
END DO
CONTAINS
! -----------------------------------------------------
! INTEGER FUNCTION intCube() :
! This function returns the cube of the argument.
! -----------------------------------------------------
intCube = Number*Number*Number
END FUNCTION intCube
! -----------------------------------------------------
! REAL FUNCTION realCube() :
! This function returns the cube of the argument.
! -----------------------------------------------------
realCube = Number*Number*Number
END FUNCTION realCube
1, 1., 1, 1.
2, 2., 8, 8.
3, 3., 27, 27.
4, 4., 64, 64.
5, 5., 125, 125.
6, 6., 216, 216.
7, 7., 343, 343.
8, 8., 512, 512.
9, 9., 729, 729.
10, 10., 1000, 1000.
DISCUSSION
• Functions intCube() and realCube() are identical except for the types of formal
arguments and returned values.
• The main program has a DO-loop that iterates Iterations times (this is a
PARAMETER, or an alias, of 10). Variable x holds the real value of integer variable i.
PROBLEM STATEMENT
The arithmetic, geometric and harmonic means of three positive numbers are defined by the
following formulas:
Write a program to read three positive numbers and use three functions to compute the
arithmetic, geometric and harmonic means.
SOLUTION
! ----------------------------------------------------------
! This program contains three functions for computing the
! arithmetic, geometric and harmonic means of three REALs.
! ----------------------------------------------------------
PROGRAM ComputingMeans
IMPLICIT NONE
REAL :: a, b, c
READ(*,*) a, b, c
WRITE(*,*) 'Input: ', a, b, c
WRITE(*,*)
WRITE(*,*) 'Arithmetic mean = ', ArithMean(a, b, c)
WRITE(*,*) 'Geometric mean = ', GeoMean(a, b, c)
WRITE(*,*) 'Harmonic mean = ', HarmonMean(a, b, c)
CONTAINS
! ----------------------------------------------------------
! REAL FUNCTION ArithMean() :
! This function computes the arithmetic mean of its
! three REAL arguments.
! ----------------------------------------------------------
REAL FUNCTION ArithMean(a, b, c)
IMPLICIT NONE
REAL, INTENT(IN) :: a, b, c
ArithMean = (a + b + c) /3.0
END FUNCTION ArithMean
! ----------------------------------------------------------
! REAL FUNCTION GeoMean() :
! This function computes the geometric mean of its
! three REAL arguments.
! ----------------------------------------------------------
REAL, INTENT(IN) :: a, b, c
GeoMean = (a * b * c)**(1.0/3.0)
END FUNCTION GeoMean
! ----------------------------------------------------------
! REAL FUNCTION HarmonMean() :
! This function computes the harmonic mean of its
! three REAL arguments.
! ----------------------------------------------------------
REAL, INTENT(IN) :: a, b, c
DISCUSSION
• Each of these functions is simple and does not require further explanation.
• Note that the main program and all three functions use the same names a, b and c.
By Scope Rule 3, they are all different entities. That is, when function ArithMean()
is using a, it is using its own local formal argument rather than the global variable a
declared in the main program.
CM AND INCH CONVERSION
PROBLEM STATEMENT
It is known that 1 cm is equal to 0.3937 inch and 1 inch is equal to 2.54 cm. Write a program to
convert 0, 0.5, 1, 1.5, ..., 8, 8.5, 9, 9.5, and 10 from cm to inch and from inch to cm.
SOLUTION
! ---------------------------------------------------------------
! This program "contains" two REAL functions:
! (1) Cm_to_Inch() takes a real inch unit and converts
! it to cm unit, and
! (2) Inch_to_cm() takes a real cm unit and converts it
! to inch unit.
! The main program uses these functions to convert 0, 0.5, 1, 1.5,
! 2.0, 2.5, ..., 8.0, 8.5, 9.0, 9.5 and 10.0 inch (resp., cm) to
! cm (resp., inch).
! ---------------------------------------------------------------
PROGRAM Conversion
IMPLICIT NONE
x = Initial
DO ! x = 0, 0.5, 1.0, ..., 9.0, 9.5, 10
IF (x > Final) EXIT
WRITE(*,*) x, 'cm = ', Cm_to_Inch(x), 'inch and ', &
x, 'inch = ', Inch_to_Cm(x), 'cm'
x = x + Step
END DO
CONTAINS
! ---------------------------------------------------------------
! REAL FUNCTION Cm_to_Inch()
! This function converts its real input in cm to inch.
! ---------------------------------------------------------------
REAL, INTENT(IN) :: cm
REAL, PARAMETER :: To_Inch = 0.3937 ! conversion factor
Cm_to_Inch = To_Inch * cm
END FUNCTION Cm_to_Inch
! ---------------------------------------------------------------
! REAL FUNCTION Inch_to_Cm()
! This function converts its real input in inch to cm.
! ---------------------------------------------------------------
REAL FUNCTION Inch_to_Cm(inch)
IMPLICIT NONE
DISCUSSION
In order for a, b and c to form a triangle, two conditions must be satisfied. First, all side lengths
must be positive:
Second, the sum of any two side lengths must be greater than the third side length:
Write a program to read in three real values and use a function for testing the conditions and
another function for computing the area. Should the conditions fail, your program must keep
asking the user to re-enter the input until the input form a triangle. Then, the other function is
used to compute the area.
SOLUTION
! --------------------------------------------------------------------
! This program uses Heron's formula to compute the area of a
! triangle. It "contains" the following functions;
! (1) LOGICAL function TriangleTest() -
! this function has three real formal arguments and tests
! to see if they can form a triangle. If they do form a
! triangle, this function returns .TRUE.; otherwise, it
! returns .FALSE.
! (2) REAL function TriangleArea() -
! this functions has three real formal arguments considered
! as three sides of a triangle and returns the area of this
! triangle.
! --------------------------------------------------------------------
PROGRAM HeronFormula
IMPLICIT NONE
REAL :: a, b, c, TriangleArea
DO
WRITE(*,*) 'Three sides of a triangle please --> '
READ(*,*) a, b, c
WRITE(*,*) 'Input sides are ', a, b, c
IF (TriangleTest(a, b, c)) EXIT ! exit if not a triangle
WRITE(*,*) 'Your input CANNOT form a triangle. Try again'
END DO
TriangleArea = Area(a, b, c)
WRITE(*,*) 'Triangle area is ', TriangleArea
CONTAINS
! --------------------------------------------------------------------
! LOGICAL FUNCTION TriangleTest() :
! This function receives three REAL numbers and tests if they form
! a triangle by testing:
! (1) all arguments must be positive, and
! (2) the sum of any two is greater than the third
! If the arguments form a triangle, this function returns .TRUE.;
! otherwise, it returns .FALSE.
! --------------------------------------------------------------------
REAL, INTENT(IN) :: a, b, c
LOGICAL :: test1, test2
! --------------------------------------------------------------------
! REAL FUNCTION Area() :
! This function takes three real number that form a triangle, and
! computes and returns the area of this triangle using Heron's formula.
! --------------------------------------------------------------------
REAL, INTENT(IN) :: a, b, c
REAL :: s
s = (a + b + c) / 2.0
Area = SQRT(s*(s-a)*(s-b)*(s-c))
END FUNCTION Area
DISCUSSION
• LOGICAL function TriangleTest() receives three REAL values. The result of the first
test condition is saved to a local LOGICAL variable test1, while the result of the
second condition is saved to another LOGICAL variable test2. Since both conditions
must be true to have a triangle, test1 and test2 are .AND.ed and the result goes
into the function name so that it could be returned.
• REAL function Area is simple and does not require further discussion. However,
please note that Area() has three formal arguments whose names are identical to
the three global variables declared in the main program. By Scope Rule 3, they are
different entities and do not cause any conflicts.
• The main program has a DO-EXIT-END DO loop. In each iteration, it asks for three
real values. These values are sent to LOGICAL function TriangleTest() for testing. If
the returned value is .TRUE., the input form a triangle and the control of execution
exits. Then, the area is computed with REAL function Area(). If the returned value is
.FALSE., this function displays a message and goes back asking for a new set of
values.
PROBLEM STATEMENT
where 0 <= r <= n must hold. Write a program that keeps reading in values for n and r, exits if
both values are zeros, uses a LOGICAL function to test if 0 <= r <= n holds, and computes
C(n,r) with an INTEGER function.
SOLUTION
! ---------------------------------------------------------------
! This program computes the combinatorial coefficient C(n,r):
!
! n!
! C(n,r) = -------------
! r! x (n-r)!
!
! It asks for two integers and uses Cnr(n,r) to compute the value.
! If 0 <= r <= n does not hold, Cnr() returns -1 so that the main
! program would know the input values are incorrect. Otherwise,
! Cnr() returns the desired combinatorial coefficient.
!
! Note that if the input values are zeros, this program stops.
! ---------------------------------------------------------------
PROGRAM Combinatorial
IMPLICIT NONE
INTEGER :: n, r, Answer
DO
WRITE(*,*)
WRITE(*,*) "Two integers n and r (0 <= r <= n) please "
WRITE(*,*) "0 0 to stop --> "
READ(*,*) n, r
IF (n == 0 .AND. r == 0) EXIT
WRITE(*,*) "Your input:"
WRITE(*,*) " n = ", n
WRITE(*,*) " r = ", r
Answer = Cnr(n, r)
IF (Answer < 0) THEN
WRITE(*,*) "Incorrect input"
ELSE
WRITE(*,*) " C(n,r) = ", Answer
END IF
END DO
CONTAINS
! ---------------------------------------------------------------
! INTEGER FUNCTION Cnr(n,r)
! This function receives n and r, uses LOGICAL function Test()
! to verify if the condition 0 <= r <= n holds, and uses
! Factorial() to compute n!, r! and (n-r)!.
! ---------------------------------------------------------------
IF (Test(n,r)) THEN
Cnr = Factorial(n)/(Factorial(r)*Factorial(n-r))
ELSE
Cnr = -1
END IF
END FUNCTION Cnr
! ---------------------------------------------------------------
! LOGICAL FUNCTION Test()
! This function receives n and r. If 0 <= r <= n holds, it
! returns .TRUE.; otherwise, it returns .FALSE.
! ---------------------------------------------------------------
LOGICAL FUNCTION Test(n, r)
IMPLICIT NONE
INTEGER, INTENT(IN) :: n, r
! ---------------------------------------------------------------
! INTEGER FUNCTION Factorial()
! This function receives a non-negative integer and computes
! its factorial.
! ---------------------------------------------------------------
Ans = 1
DO i = 1, k
Ans = Ans * i
END DO
Factorial = Ans
END FUNCTION Factorial
In the sample output above, please note the error messages indicating that condition 0 <=
r <= n does not hold. Please also note that the program stops when the input values are 0
and 0.
DISCUSSION
PROBLEM STATEMENT
We have discussed Newton's Method for computing the square root of a positive number.
Let the given number be b and let x be a rough guess of the square root of b. Newton's
method suggests that a better guess, New x can be computed as follows:
One can start with b as a rough guess and compute New x; from New x, one can generate a even
better guess, until two successive guesses are very close. Either one could be considered as the
square root of b.
Write a function MySqrt() that accepts a formal argument and uses Newton's method to
computes its square root. Then, write a main program that reads in an initial value, a final value,
and a step size, and computes the square roots of these successive values with Newton'e method
and Fortran's SQRT() function, and determines the absolute error.
SOLUTION
! ---------------------------------------------------------------
! This program contains a function MySqrt() that 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
CONTAINS
! ---------------------------------------------------------------
! REAL FUNCTION MySqrt()
! This function uses Newton's method to compute an approximate
! of a positive number. If the input value is zero, then zero is
! returned immediately. For convenience, the absolute value of
! the input is used rather than kill the program when the input
! is negative.
! ---------------------------------------------------------------
DISCUSSION
This program has nothing special. Please refer to the discussion of Newton's method for the
computation details of function MySqrt(). However, there is one thing worth to be
mentioned. Since the formal argument Input is declared with INTENT(IN), it cannot be
changed in function MySqrt(). Therefore, the value of the formal argument Input is copied
to X and used in square root computation.
PROBLEM STATEMENT
We have seen Greatest Common Divisor computation. This problem uses the same idea; but
the computation is performed with a function.
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.
!
! Euclid's algorithm is implemented as an INTEGER function
! GCD().
! ---------------------------------------------------------
PROGRAM GreatestCommonDivisor
IMPLICIT NONE
INTEGER :: a, b
CONTAINS
! ---------------------------------------------------------
! INTEGER FUNCTION GCD():
! This function receives two INTEGER arguments and
! computes their GCD.
! ---------------------------------------------------------
DO
c = MOD(a, b)
IF (c == 0) EXIT
a = b
b = c
END DO
GCD = b
END FUNCTION GCD
DISCUSSION
Nothing special is here. As in the previous example, since x and y are declared with
INTENT(IN), their values cannot be modified and therefore their values are copies to a and
b to be used in other computation.
PROBLEM STATEMENT
We have discussed a method for finding all prime numbers in the range of 2 and N
previously. In fact, one can design a function with an INTEGER formal argument and returns
.TRUE. if the argument is a prime number. Then, it is used to test if the integers in the
range of 2 and N are integers.
SOLUTION
! --------------------------------------------------------------------
! This program finds all prime numbers in the range of 2 and an
! input integer.
! --------------------------------------------------------------------
PROGRAM Primes
IMPLICIT NONE
Range = GetNumber()
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, ...
IF (Prime(Number)) THEN
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
CONTAINS
! --------------------------------------------------------------------
! INTEGER FUNCTION GetNumber()
! This function does not require any formal argument. It keeps
! asking the reader for an integer until the input value is greater
! than or equal to 2.
! --------------------------------------------------------------------
INTEGER :: Input
! --------------------------------------------------------------------
! LOGICAL FUNCTION Prime()
! This function receives an INTEGER formal argument Number. If it
! is a prime number, .TRUE. is returned; otherwise, this function
! returns .FALSE.
! --------------------------------------------------------------------
DISCUSSION
• Function GetNumber() has no formal arguments. It keeps asking the user to input
an integer that is greater than or equal to two. The valid input is returned as the
function value.
• The core part of this program is LOGICAL function Prime(). It receives an INTEGER
formal argument Number and returns .TRUE. if Number is a prime number. For the
working detail and logic of this function, please click here to bring you to the
example discussed previously.
PROBLEM STATEMENT
Given a continuous equation f(x)=0 and two values a and b (a < b), if f(a)*f(b) < 0 (i.e., f(a) and
f(b) have opposite signs), it can be proved that there exists a root of f(x)=0 between a and b.
More precisely, there exists a c, a <= c <= b, such that f(c)=0 holds.
This result provides us with a method for solving equations. If we take the midpoint of a and b,
c=(a+b)/2, and computes its function value f(c), we have the following cases:
1. If f(c) is very small (i.e., smaller than a tolerance value), then c can be considered as
a root of f(x)=0 and we are done.
2. Otherwise, since f(a) and f(b) have opposite signs, the sign of f(c) is either identical
to that of f(a) or that of f(b).
o If the sign of f(c) is different from that of f(a), then since f(a) and f(c) have
opposite signs, f(x)=0 has a root in the range of a and c.
o If the sign of f(c) is different from that of f(b), then since f(b) and f(c) have
opposite signs, f(x)=0 has a root in the range of c and b.
3. Therefore, if the original interval [a,b] is replaced with [a,c] in the first case or
replaced with [c,b] in the second case, the length of the interval is reduced by half. If
continue this process, after a number of steps, the length of the interval could be
very small. However, since this small interval still contains a root of f(x)=0, we
actually find an approximation of that root!
Write a program that contains two functions: (1) Funct() - the function f(x) and (2) Solve()
- the equation solver based on the above theory. Then, reads in a and b and uses function
Solve() to find a root in the range of a and b. Note that before calling Solve, your program
should check if f(a)*f(b)<0 holds.
Since this process keeps dividing the intervals into two equal halves, it is usually referred to as
the bisection method. It is also known as Bozano's method.
SOLUTION
! --------------------------------------------------------------------
! This program solves equations with the Bisection Method. Given
! a function f(x) = 0. The bisection method starts with two values,
! a and b such that f(a) and f(b) have opposite signs. That is,
! f(a)*f(b) < 0. Then, it is guaranteed that f(x)=0 has a root in
! the range of a and b. This program reads in a and b (Left and Right
! in this program) and find the root in [a,b].
! In the following, function f() is REAL FUNCTION Funct() and
! solve() is the function for solving the equation.
! --------------------------------------------------------------------
PROGRAM Bisection
IMPLICIT NONE
CONTAINS
! --------------------------------------------------------------------
! REAL FUNCTION Funct()
! This is for function f(x). It takes a REAL formal argument and
! returns the value of f() at x. The following is sample function
! with a root in the range of -10.0 and 0.0. You can change the
! expression with your own function.
! --------------------------------------------------------------------
! --------------------------------------------------------------------
! REAL FUNCTION Solve()
! This function takes Left - the left end, Right - the right end,
! and Tolerance - a tolerance value such that f(Left)*f(Right) < 0
! and find a root in the range of Left and Right.
! This function works as follows. Because of INTENT(IN), this
! function cannot change the values of Left and Right and therefore
! the values of Left and Right are saved to a and b.
! Then, the middle point c=(a+b)/2 and its function value f(c)
! is computed. If f(a)*f(c) < 0, then a root is in [a,c]; otherwise,
! a root is in [c,b]. In the former case, replacing b and f(b) with
! c and f(c), we still maintain that a root in [a,b]. In the latter,
! replacing a and f(a) with c and f(c) will keep a root in [a,b].
! This process will continue until |f(c)| is less than Tolerance and
! hence c can be considered as a root.
! --------------------------------------------------------------------
A root is -0.89050293
The following output shows that the function values of the input do not have opposite signs
and hence program stops.
DISCUSSION
In many previous example, there are several internal functions packed at the end of the main
program. In fact, many of them such as Factorial(), Combinatorial(), GCD(), and Prime() are
general functions that can also be used in other programs. To provide the programmers with a
way of packing commonly used functions into a few tool-boxes, Fortran 90 has a new capability
called modules. It has a syntactic form very similar to a main program, except for something that
are specific to modules.
SYNTAX
The following is the syntax of a module:
MODULE module-name
IMPLICIT NONE
[specification part]
CONTAINS
[internal-functions]
END MODULE module-name
SHORT EXAMPLES
Here are some short examples of modules:
• The following is a very simple module. It has the specification part and does not have
any internal function. The specification part has two REAL PARAMETERs, namely PI
and g and one INTEGER variable Counter.
MODULE SomeConstants
IMPLICIT NONE
REAL, PARAMETER :: PI = 3.1415926
REAL, PARAMETER :: g = 980
INTEGER :: Counter
END MODULE SomeConstants
• The following module SumAverage does not have any specification part (hence no
IMPLICIT NONE); but it does contain two functions, Sum() and Average(). Please
note that function Average() uses Sum() to compute the sum of three REAL
numbers.
MODULE SumAverage
CONTAINS
REAL FUNCTION Sum(a, b, c)
IMPLICIT NONE
REAL, INTENT(IN) :: a, b, c
Sum = a + b + c
END FUNCTION Sum
MODULE DegreeRadianConversion
IMPLICIT NONE
REAL, PARAMETER :: PI = 3.1415926
REAL, PARAMETER :: Degree180 = 180.0
Once a module is written, its global entities (i.e., global PARAMETERs, global variables and
internal functions) can be made available to other modules and programs. The program or
module that wants to use a particular module must have a USE statement at its very beginning.
The USE statement has one of the following forms:
SYNTAX
The following form is the syntax of a module:
USE module-name
The first indicates that the current program or module wants to use the module whose
name is module-name. For example, the following main program indicates that it wants
to use the content of module SomeConstants:
PROGRAM MainProgram
USE SomeConstants
IMPLICIT NONE
..........
END PROGRAM MainProgram
Once a USE is specified in a program or in a module, every global entities of that used
module (i.e., PARAMETERs, variables, and internal functions) becomes available to this
program or this module. For example, if module SomeConstants is:
MODULE SomeConstants
IMPLICIT NONE
REAL, PARAMETER :: PI = 3.1415926
REAL, PARAMETER :: g = 980
INTEGER :: Counter
END MODULE SomeConstants
However, under many circumstances, a program or a module does not want to use
everything of the used module. For example, if program MainProgram only wants to
use PARAMETER PI and variable Counter and does not want to use g, then the second
form becomes very useful. In this case, one should add the keyword ONLY followed by a
colon :, followed by a list of names that the current program or module wants to use.
PROGRAM MainProgram
USE SomeConstants, ONLY: PI, Counter
IMPLICIT NONE
..........
END PROGRAM MainProgram
USE with ONLY: is very handy, because it could only "import" those important and
vital information and "ignore" those un-wanted ones.
• There is a third, not recommended form, that can help to rename the names of a
module locally. If a module has a name abc, in a program with a USE, one can use a
new name for abc. The way of writing this renaming is the following:
• new-name => name-in-module
PROGRAM MainProgram
USE SomeConstants, ONLY: PI, MyCounter => Counter
IMPLICIT NONE
..........
END PROGRAM MainProgram
The above example wants to use PI of module SomeConstants. In this case, when
program MainProgram uses PI, it actually uses the PI of module SomeConstants.
Program MainProgram also uses Counter of module SomeConstants; but, in this
case, since there is a renaming, when MainProgram uses MyCounter it actually
uses Counter of module SomeConstants.
Renaming does not require ONLY:. In the following, MainProgram can use all contents
of module SomeConstants. When MainProgram uses PI and g, it uses the PI and g of
module SomeConstants; however, when MainProgram uses MyCounter, it actually
uses Counter of module SomeConstants.
PROGRAM MainProgram
USE SomeConstants, MyCounter => Counter
IMPLICIT NONE
..........
END PROGRAM MainProgram
Why do we need renaming? It is simple. In your program, you may have a variable
whose name is identical to an entity of a module that is being USEed. In this case,
renaming the variable name would clear the ambiguity.
PROGRAM MainProgram
USE SomeConstants, GravityConstant => g
IMPLICIT NONE
INTEGER :: e, f, g
..........
END PROGRAM MainProgram
In the above example, since MainProgram has a variable called g, which is the
same as PARAMETER g in module SomeConstants. By renaming g of
SomeConstants, MainProgram can use variable g for the variable and
GravityConstant for the PARAMETER g in module SomeConstants.
Normally, your programs and modules are stored in different files, all with filename suffix .f90.
When you compile your program, all involved modules must also be compiled. For example, if
your program is stored in a file main.f90 and you expect to use a few modules stored in files
compute.f90, convert.f90 and constants.f90, then the following command will compile your
program and all three modules, and make an executable file a.out
Different compilers may have different "personalities." This means the way of compiling
modules and your programs may be different from compilers to compilers. If you have
several modules, say A, B, C, D and E, and C uses A, D uses B, and E uses A, C and D, then
the safest way to compile your program is the following command:
You may also compile your modules separately. For example, you may want to write and
compile all modules before you start working on your main program. The command for you to
compile a single program or module without generating an executable is the following:
f90 -c compute.f90
where -c means "compile the program without generating an executable." The output from
Fortran compiler is a file whose name is identical to the program file's name but with a file
extension .o. Therefore, the above command generates a file compute.o. The following
commands compile all of your modules:
f90 -c compute.f90
f90 -c convert.f90
f90 -c constants.f90
After compiling these modules, your will see at least three files, compute.o, convert.o and
constants.o.
After completing your main program, you have two choices: (1) compile your main program
separately, or (2) compile your main with all "compiled" modules. In the former, you perhaps
use the following command to compile your main program:
f90 -c main.f90
Then, you will have a file main.o. Now you have four .o files main.o, compute.o,
convert.o and constants.o. To pull them into an executable, you need
If you want compile your main program main.f90 with all .o files, then you need
PROBLEM STATEMENT
where 0 <= r <= n must hold. Write a module that contains two functions: (1) Factorial() and
(2) Combinatorial(). The former computes the factorial of its argument, while the latter uses the
former to compute the combinatorial coefficient. Then, write a main program that uses this
module.
SOLUTION
The following is the desired module:
! --------------------------------------------------------------------
! MODULE FactorialModule
! This module contains two procedures: Factorial(n) and
! Combinatorial(n,r). The first computes the factorial of an integer
! n and the second computes the combinatorial coefficient of two
! integers n and r.
! --------------------------------------------------------------------
MODULE FactorialModule
IMPLICIT NONE
CONTAINS
! --------------------------------------------------------------------
! FUNCTION Factorial() :
! This function accepts a non-negative integers and returns its
! Factorial.
! --------------------------------------------------------------------
! --------------------------------------------------------------------
! FUNCTION Combinarotial():
! This function computes the combinatorial coefficient C(n,r).
! If 0 <= r <= n, this function returns C(n,r), which is computed as
! C(n,r) = n!/(r!*(n-r)!). Otherwise, it returns 0, indicating an
! error has occurred.
! --------------------------------------------------------------------
INTEGER, INTENT(IN) :: n, r
INTEGER :: Cnr
! --------------------------------------------------------------------
! PROGRAM ComputeFactorial:
! This program uses MODULE FactorialModule for computing factorial
! and combinatorial coefficients.
! --------------------------------------------------------------------
PROGRAM ComputeFactorial
USE FactorialModule ! use a module
IMPLICIT NONE
INTEGER :: N, R
DISCUSSION
PROBLEM STATEMENT
Trigonometric functions (i.e., sin(x) and cos(x)) use radian for their argument. Using modules,
you can design your own trigonometric functions that use degree. Write a module that contains
functions for converting radian to degree and degree to radian and sin(x) and cos(x) with
arguments in degree rather than in radian.
SOLUTION
The following is the desired module:
! --------------------------------------------------------------------
! MODULE MyTrigonometricFunctions:
! This module provides the following functions and constants
! (1) RadianToDegree() - converts its argument in radian to
! degree
! (2) DegreeToRadian() - converts its argument in degree to
! radian
! (3) MySIN() - compute the sine of its argument in
! degree
! (4) MyCOS() - compute the cosine of its argument
! in degree
! --------------------------------------------------------------------
MODULE MyTrigonometricFunctions
IMPLICIT NONE
CONTAINS
! --------------------------------------------------------------------
! FUNCTION RadianToDegree():
! This function takes a REAL argument in radian and converts it to
! the equivalent degree.
! --------------------------------------------------------------------
! --------------------------------------------------------------------
! FUNCTION DegreeToRadian():
! This function takes a REAL argument in degree and converts it to
! the equivalent radian.
! --------------------------------------------------------------------
! --------------------------------------------------------------------
! FUNCTION MySIN():
! This function takes a REAL argument in degree and computes its
! sine value. It does the computation by converting its argument to
! radian and uses Fortran's sin().
! --------------------------------------------------------------------
MySIN = SIN(DegreeToRadian(x))
END FUNCTION MySIN
! --------------------------------------------------------------------
! FUNCTION MySIN():
! This function takes a REAL argument in degree and computes its
! cosine value. It does the computation by converting its argument to
! radian and uses Fortran's cos().
! --------------------------------------------------------------------
MyCOS = COS(DegreeToRadian(x))
END FUNCTION MyCOS
! -----------------------------------------------------------------------
! PROGRAM TrigonFunctTest:
! This program tests the functions in module MyTrigonometricFunctions.
! Module MyTrigonometricFunctions is stored in file trigon.f90.
! Functions in that module use degree rather than radian. This program
! displays the sin(x) and cos(x) values for x=-180, -170, ..., 0, 10, 20,
! 30, ..., 160, 170 and 180. Note that the sin() and cos() function
! in module MyTrigonometricFunctions are named MySIN(x) and MyCOS(x).
! -----------------------------------------------------------------------
PROGRAM TrigonFunctTest
USE MyTrigonometricFunctions ! use a module
IMPLICIT NONE
Value of PI = 3.1415925
All global entities of a module, by default, can be accessed by a program or another module
using the USE statement. But, it is possible to set some restrictions that some entities are private.
A private entity of a module can only be accessed within that module. On the other hand, one
can explicitly list those entities that can be accessed from outside. This is done with the PUBLIC
and PRIVATE statements:
SYNTAX
The following is the syntax of a module:
MODULE TheForce
IMPLICIT NONE
CONTAINS
INTEGER FUNCTION VolumeOfDeathStar()
..........
END FUNCTION WolumeOfDeathStar
..........
END MODULE TheForce
A PROGRAMMING EXAMPLE
In a previous example of using degree in trigonometric functions, four constants and four
functions are defined. But, most of them are used in and meaningful to the module
MyTrigonometricFunctions. Thus, one can make them private so that they cannot be
accessed from outside of this module. Here is a rewritten version:
! --------------------------------------------------------------------
! MODULE MyTrigonometricFunctions:
! This module provides the following functions and constants
! (1) RadianToDegree() - converts its argument in radian to
! degree
! (2) DegreeToRadian() - converts its argument in degree to
! radian
! (3) MySIN() - compute the sine of its argument in
! degree
! (4) MyCOS() - compute the cosine of its argument
! in degree
! --------------------------------------------------------------------
MODULE MyTrigonometricFunctions
IMPLICIT NONE
CONTAINS
! --------------------------------------------------------------------
! FUNCTION RadianToDegree():
! This function takes a REAL argument in radian and converts it to
! the equivalent degree.
! --------------------------------------------------------------------
! --------------------------------------------------------------------
! FUNCTION DegreeToRadian():
! This function takes a REAL argument in degree and converts it to
! the equivalent radian.
! --------------------------------------------------------------------
! --------------------------------------------------------------------
! FUNCTION MySIN():
! This function takes a REAL argument in degree and computes its
! sine value. It does the computation by converting its argument to
! radian and uses Fortran's sin().
! --------------------------------------------------------------------
MySIN = SIN(DegreeToRadian(x))
END FUNCTION MySIN
! --------------------------------------------------------------------
! FUNCTION MySIN():
! This function takes a REAL argument in degree and computes its
! cosine value. It does the computation by converting its argument to
! radian and uses Fortran's cos().
! --------------------------------------------------------------------
MyCOS = COS(DegreeToRadian(x))
END FUNCTION MyCOS
In this module, there are four PARAMETERs. Of these four, only PI is not listed as PRIVATE
and hence can be accessed from outside of this module. There are four internal functions,
MySIN(), MyCOS(), RadianToDegree() and DegreeToRadian(). The former two are listed as
PUBLIC and can be accessed from outside of this module. The latter two are listed as
PRIVATE and therefore cannot be accessed from outside of this module.
Note that if PI is also made PRIVATE, then the main program will have a mistake since it
displays the value of PI:
PROGRAM TrigonFunctTest
USE MyTrigonometricFunctions
IMPLICIT NONE
..........
WRITE(*,*) 'Value of PI = ', PI ! PI cannot be used here
..........
END PROGRAM TrigonFunctTest