Escolar Documentos
Profissional Documentos
Cultura Documentos
Fortran 90 Tutorial
Dr. C.-K. Shene
Associate Professor
Department of Computer Science
Michigan Technological University
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/fortran.html8/5/2006 8:01:06 PM
Introduction and Basic Fortran
Introduction
Program Structure
Comments
Continuation Lines
Basic Fortran
Alphabets
Constants
Identifiers
Variables and Their Types
Variable Declarations
Assigning a Constant a Name - PARAMETER attribute
Initializing Variables
Arithmetic Operators
Simple Mode Arithmetic Expressions
Mixed Mode Arithmetic Expressions
The Assignment Statement
Intrinsic Functions
List-Directed Input: The READ Statement
List-Directed Output: The WRITE Statement
Programming Examples:
Three Programming Traps
Computing Means
Quadratic Equation Solver
The Length of a Parabola Segment
Projectile motion (intrinsic functions)
Character Operator and Substrings (Optional)
Download my course overheads
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/intro.html8/5/2006 8:01:34 PM
Program structure
Program Structure
PROGRAM program-name
IMPLICIT NONE
[specification part]
[execution part]
[subprogram part]
END PROGRAM program-name
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/chap01/struct.html8/5/2006 8:01:48 PM
Fortran identifiers
Fortran Identifiers
❍ I, X
● Incorrect Examples:
❍ M.T.U.: only letters, digits, and underscores can be used
● Fortran has many keywords such as INTEGER, REAL, PARAMETER, PROGRAM, END, IF, THEN,
ELSE, DO, just name a few; however, Fortran does not have any reserved words. More precisely, a
programmer can use these keywords as identifiers. Therefore, END, PROGRAM, DO are perfectly legal
Fortran identifiers. However, this is definitely not a good practice.
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.
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/chap02/id.html8/5/2006 8:01:56 PM
Fortran comments
Fortran Comments
Comments should be used liberally to improve readability. The following are the rules for making comments:
● All characters following an exclamation mark, !, except in a character string, are commentary, and are ignored by the
compiler.
PROGRAM TestComment1
..........
READ(*,*) Year ! read in the value of Year
..........
Year = Year + 1 ! add 1 to Year
..........
END PROGRAM TestComment1
PROGRAM TestComment3
..........
READ(*,*) Count
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/chap01/comment.html8/5/2006 8:02:03 PM
Fortran alphabets
Fortran Alphabets
● 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
' " ( ) * + - / : = _
! & $ ; < > % ? , .
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/chap02/alphabet.html8/5/2006 8:02:12 PM
Fortran continuation lines
In Fortran, a statement must start on a new line. If a statement is too long to fit on a line, it can be continued with
the following methods:
● If a line is ended with an ampersand, &, it will be continued on the next line.
● Continuation is normally to the first character of the next non-comment line.
The above is equivalent to the following, since the commentis 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
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 ThisIsALongand VariableName. In this way, a token (name and number) can
be split over two lines. However, this is not recommended
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/chap01/continue.html8/5/2006 8:02:34 PM
Fortran Constants
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.
❍ Incorrect Examples:
■ 5- and 7+: the optional sign must precede the string of digits
● Real Constants: There are two representations, decimal representation and exponential representation.
❍ Decimal Representation: A decimal point must be presented, but no commas are allowed. A real constant
■ Incorrect Examples:
mantissa or fractional part), followed by the letter E or e, followed by an integer (the exponent).
■ Correct Examples
■ Incorrect Examples
■ ' ' and " ": content = a single space and length = 1
■ 'John Dow #2' and "John Dow #2": content = John Dow #2 and length = 11
❍ Incorrect Examples:
■ 'Hi" and "Hi': the opening and closing quotes do not match.
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.
❍ Correct Examples:
❍ Incorrect Examples:
■ 'Tech's seminar': the single quote between h and s should be written twice.
A Fortran variable can be considered as a box that is capable of holding a single value of certain type. Thus, a variable has
a name, the variable name and a type. The way of choosing a name for a variable must fulfill the rules of composing a
Fortran identifier. The type of a variable can be one of the following:
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/chap02/var-type.html8/5/2006 8:02:49 PM
Fortran Variable Declarations
Declaring the type of a Fortran variable is done with type statements. It has the following form:
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:
❍ FirstName, LastName and OtherName are character variables that can hold a string of no more than 20
characters:
● Use CHARACTER(i) to declare character variables of length i. That is, there is no LEN= in the parenthesis. For
examples,
❍ Name and Street are character variables that can hold a string of no more than 15 characters:
❍ FirstName, LastName and OtherName are character variables that can hold a string of no more than 20
characters:
● If a variable can only hold a single character, the length part can be removed. The following three declarations are all
equivalent:
Here, variables letterand digitcan 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.
Here, variables Cityand BOXcan hold a string of no more than 10 characters, Nationcan hold a string of no more
than 20 characters, and bugcan 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.
Here, the actual lengths of variables Titleand Positionare unknown and will be determined elsewhere.
In many places, one just wants to assign a name to a particular value. For example, keep typing 3.1415926 is tedious. In this
case, one could assign a name, say PI, to 3.1415926 so that one could use PI rather than 3.1415926. To assign a name to a
value, one should do the following:
● 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:
● 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:
● 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).
● In the example below, Name is a name for the string 'John' and State is a name for the string "Utah"
"Smith" is 5 while the length of Name is 4, the string is truncated to the right and the content of Name is
"Smit"
❍ 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 "
● 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.
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. Using 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 first defines three named integer constants with PARAMETER and uses these values to
initialize two integer variables. Thus, variables Pay and Received are initialized to have values 4350 (=10*435) and
8 (3+5), respectively.
● 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.
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/chap02/var-init.html8/5/2006 8:02:53 PM
Arithmetic Operators
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.
● 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
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/chap02/operator.html8/5/2006 8:02:55 PM
Single Mode Arithmetic Expressions
An arithmetic expression is an expression using additions +, subtractions -, multiplications *, divisions /, and exponentials
**. A single mode arithmetic expression is an expression all of whose operands are of the same type (i.e. INTEGER,
REAL or COMPLEX). However, only INTEGER and REAL will be covered in this note. Therefore, those values or
variables in a single mode arithmetic expression are all integers or real numbers.
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.
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:
3 * 5 - 4
In the above expression, in the left to right scan, operator *is encountered first. Since the the operator -is
lower, 3 * 5is evaluated first transforming the given expression to 15 - 4. Hence, the result is 11.
❍ 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).
❍ if the next one is higher than the current, the scan should continue with the next operator. For example,
consider the following expression:
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 ** 3is 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 the following example, x**0.25 is equivalent to computing the fourth root of x. In general, taking the k-th root of
x is equivalent to x**(1.0/k) in Fortran, where k is a real number.
If operands in an expression contains both INTEGER and REAL constants or variables, this is a mixed mode arithmetic
expression.
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:
❍ if the operands of this operator are of the same type, compute the result of this operator.
❍ 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 2.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.
In the following, brackets will be used to indicated the order of evaluation and braces will be used to indicated an integer-to-
real conversion.
● 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
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.
❍ If the type of the variable is INTEGER while the type of the result is REAL, the fractional part, including
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
● In the following, PI is a PARAMETER and is an alias of 3.1415926. The first assignment statement puts integer
value 5 into integer variable Radius. The expression in the second assignment is first evaluated, yielding a result
78.539815, which is then saved into REAL variable Area.
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.
Initially, A and B are initialized to 3 and 5, respectively, while C is uninitialized. The first assignment statement puts
A's value into C, making A=3, B=5 and C=3.
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
Fortran provides many commonly used functions, called intrinsic functions. To use a Fortran function, one needs to
understand the following items:
● 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:
Return
Function Meaning Arg. Type
Type
INTEGER INTEGER
ABS(x) absolute value of x
REAL REAL
SQRT(x) square root of x REAL REAL
SIN(x) sine of x radian REAL REAL
COS(x) cosine of x radian REAL REAL
TAN(x) tangent of x radian REAL REAL
ASIN(x) arc sine of x REAL REAL
ACOS
arc cosine of x REAL REAL
(x)
ATAN
arc tangent of x REAL REAL
(x)
EXP(x) exp(x) REAL REAL
natural logarithm of
LOG(x) REAL REAL
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:
Return
Function Meaning Arg. Type
Type
● Other functions:
Return
Function Meaning Arg. Type
Type
MAX(x1, x2, ..., maximum of x1, x2, ... INTEGER INTEGER
xn) xn REAL REAL
INTEGER INTEGER
MIN(x1, x2, ..., xn) minimum of x1, x2, ... xn
REAL REAL
remainder x - INT(x/y) INTEGER INTEGER
MOD(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.
List-directed input is carried out with the Fortran READ statements. The READ statement can read input values into a set
of variables from the keyboard.
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
● 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
● 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 READstatements are used to read the following input lines,
100 200
300 400 500
600
then I, J, K, L, Mand Nwill 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
Variables I, Jand Kreceive 100, 200 and 300, respectively. Since the second READstarts with a new line, L, Mand
Nreceive 500, 600 and 700, respectively. 400 on the first input line is lost. The next READwill start reading with the
third line, picking up 900. Hence, 800 is lost.
● A limited type conversion is possible in a READ statement. If the input value is an integer and the corresponding
variable is of REAL type, the input integer will be convert to a real number.
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 READreads 100 and 200 into Pand Qand 300 is lost. The second READstarts with a new input line, which
is the second one. It does not read in anything. The third READstarts with the third line and reads 700 and 800 into
Rand 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.
Listed-directed output is carried with the Fortran WRITE statement. The WRITE statement can display the results of a set
of expressions and character strings. In general, WRITE displays the output on the screen.
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.
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
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 Smithbecomes Smitand the original TEXASbecomes 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)
Program Output
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.
The parenthesis surrounding X * Y * Z cannot be removed; otherwise, the expression X * Y * Z **(1.0/3.0) means
X * Y * (Z **(1.0/3.0)) since ** has a priority higher than that of *.
● The parenthesis in the third assignment cannot be removed either. Why?
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
A, B, C Please :
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 Returnkey. Then, these values are stored in a, band 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.
Concatenation Operator //
Fortran has only one character operator, the concatenation operator //. The concatenation operator cannot be used with
arithmetic operators. Given two strings, s1 and s2 of lengths m and n, respectively, the concatenation of s1 and s2, written
as s1 // s2, contains all characters in string s1, followed by all characters in string s2. Therefore, the length of s1 // s2 is m
+n.
● 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:
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
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"
Selective Execution
Selective Execution
LOGICAL Type and Variables
LOGICAL Input and Output
Relational Operators
LOGICAL Operators and Expressions
IF-THEN-ELSE-END IF Statement
Form 1: IF-THEN-ELSE-END IF
Form 2: IF-THEN-END IF
Form 3: Logical IF
Programming Example 1: Quadratic Equation Solver
Programming Example 2: Final Mark Computation
Programming Example 3: Heron's Formula for Computing Triangle Area
Nested IF-THEN-ELSE-END IF
IF-THEN-ELSE IF-END IF
Programming Examples:
Quadratic Equation Solver: Again
Quadratic Equation Solver: Revisited
Sort Three Numbers
SELECT CASE Statement
Programming Example 1: Computing Letter Grade
Programming Example 2: Character Testing
Download my course overheads
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/select.html8/5/2006 8:04:19 PM
LOGICAL Type and Variables
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.
● 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.
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/chap03/log-type.html8/5/2006 8:04:23 PM
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.
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/chap03/log-io.html8/5/2006 8:04:25 PM
Relational Operators
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:
This means that a relational operator can be evaluated only if its two operands have been evaluated. For
example, in
a + b /= c*c + d*d
expressions a+b and c*c + d*d are evaluated before the relational operator /= is evaluated.
● If you are not comfortable in writing long relational expressions, use parenthesis. Thus,
● Although a < b < c is legal in mathematics, you cannot write comparisons this way in Fortran. The meaning of
this expression is a < b and b < c. You should use logical operator to achieve this.
Examples
In the above, please note the left-to-right evaluation order and the type conversion making 220 to 220.0 before
carrying out /=
Characters are encoded. Different standards (e.g. BCD, EBCDIC and ASCII) may have different encoding schemes.
To write a program that can run on all different kind of computers and get the same comparison results, one can
only assume the following ordering sequences:
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
If you compare characters in different sequences such as 'A' < 'a' and '2' >= 'N', you are asking for trouble since
different encoding methods may produce different answers. Moreover, do not assume there exists a specific order
among upper and lower case letters, digits, and special symbols. Thus, '+' <= 'A', '*' >= '%', 'u' > '$', and '8' >= '?'
make no sense. However, you can always compare if two characters are equal or not equal. Hence, '*' /= '9', 'a' ==
'B' and '8' == 'b' are perfectly fine.
● 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
❍ both strings have consumed all of their characters, they are equal since all of their corresponding
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.
● Compare "01357" and "013579"
0 1 3 5 7
= = = = =
0 1 3 5 7 9
Since all compared characters are equal and the first string is shorter, "01357" < "013579" holds.
● What is the result of "DOG" < "FOX"?
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.
Truth Tables
The evaluation of logical expressions is determined by truth tables. Let us start with the .NOT. operator.
Operand Result
. .
.TRUE.
NOT. 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.).
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. .FALSE
TRUE.
.
.TRUE. .TRUE.
TRUE.
. . .
FALSE. TRUE. FALSE.
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.
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.
.
.TRUE. .TRUE.
FALSE.
. .
.TRUE.
FALSE. FALSE.
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.
In the above, since .NOT.has the highest priority, it is evaluated first. Now, look at the following example:
● 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
a <= number
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
The IF-THEN-END IF form is a simplification of the general IF-THEN-ELSE-END IF form with the ELSE part
omitted:
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
● In many cases, it is required to do something when certain condition is satisfied; otherwise, do nothing. This is
exactly what we need the form of IF-THEN-END IF. In the following, an INTEGER variable Counter is used for
counting something. When its value is a multiple of 10, a blank line is displayed.
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
● In many cases, it is required to do something when certain condition is satisfied; otherwise, do nothing. This is
exactly what we need the form of IF-THEN-END IF. In the following, an INTEGER variable Counter is used for
counting something. When its value is a multiple of 10, a blank line is displayed.
INTEGER :: Counter
● The following is wrong since the one-statement if a logical IF can not be another IF statement.
INTEGER :: a, b, c
From the above examples, one can easily see that if the THEN part has exactly one statement and there is no ELSE, the
logical IF statement can save some space making a program a little shorter. But, my advice is that don't use it whenever it is
possible.
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.
● 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
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
ELSE
WRITE(*,*) 'Pass Status : FAIL'
END IF
● 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.
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 +
x> display -
0 x<
0 display
0
Converting to a IF-THEN-ELSE-END IF construct is easy since the above box is almost identical to that. So, here
is our answer:
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:
display -x
display
x<
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:
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
The Nested IF-THEN-ELSE-END IF statement could produce a deeply nested IF statement which is difficult to read.
There is a short hand to overcome this problem. It is the IF-THEN-ELSE IF-END-IF version. Its syntax is shown below:
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 xis less than 50, 'F'is assigned to Grade. If xis greater than or equal to 50, the execution continue with the
first ELSE IFwhere x < 60is tested. If it is .TRUE., 'D'is assigned to Grade. Note that one can reach the test of x <
60simply because the test x < 50is .FALSE.. Therefore, when reaches x < 60, we are sure that x >= 50must hold and
as a result, Gradereceives 'D'if xis 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:
Result = b
ELSE
Result = c
END IF
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. 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
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(*,*)
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
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(*,*)
Since we have been doing the quadratic part in several similar examples, the following concentrates on the order part of the
program.
● 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
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.
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:
! -------------------------------------------------------
! This program reads in three INTEGERs and displays them
! in ascending order.
! -------------------------------------------------------
PROGRAM Order
IMPLICIT NONE
INTEGER :: a, b, c
READ(*,*) a, b, c
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:
where statements-1, statements-2, statements-3, ..., statements-n and statements-DEFAULT are sequences of executable
statements, including the SELECT CASE statement itself, and selector is an expression whose result is of type INTEGER,
CHARACTER or LOGICAL (i.e., no REAL type can be used for the selector). The label lists label-list-1, label-list-2,
label-list-3, ..., and label-list-n are called case labels.
A label-list is a list of labels, separated by commas. Each label must be one of the following forms. In fact, three of these
four are identical to an extent specifier for substrings:
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.
● If the result is not in any one of the label lists, there are two possibilities:
❍ if CASE DEFAULT is there, then the sequence of statements in statements-DEFAULT are executed,
Examples
● The following uses Class to execute a selection. If Class is 1, Freshman is displayed; if Class is 2, Sophomore is
displayed; if Class is 3, Junior is displayed; if Class is 4, Senior is displayed; and if Class is none of the above,
Hmmmm, I don't know is displayed. After displaying one of the above, Done is displayed.
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
MS = MS + 1
CASE ("BS")
BS = BS + 1
CASE DEFAULT
Others = Others + 1
END SELECT
● 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
● The following program uses the value of Number to determine the value of Range.
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:
Range Grade
>= 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
!
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.
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
How do you input a character to your program? The easiest way is using something like 'Y', "g" and '-'. That is, use single
or double quotes.
● 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.
Repetitive Execution
Repetitive Execution
Counting DO-Loop
Programming Examples:
Counting Positive and Negative Input Values
Computing Arithmetic, Geometric and Harmonic Means
Computing Factorial
General DO-Loop with EXIT
Programming Examples:
Determining the Minimum and Maximum of Input Data
Computing the Square Root of a Positive Number
Computing EXP(x)
Computing the Greatest Common Divisor of Two Positive Integers
Checking If a Positive Integer Is a Prime Number
Nested DO-Loop
Programming Examples:
Computing Classes Averages
Computing a Set of Values of EXP(x)
Armstrong Numbers
Finding All Primes in the Range of 2 and N
Finding all Prime factors of a Positive Integer
Handling End of File: the READ Statement Revisited
Computing Arithmetic, Geometric and Harmonic Means: Revisited
The DO-CYCLE Construct and a Programming Example (Optional)
Download my course overheads
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/loop.html8/5/2006 8:05:43 PM
Counting DO-Loop
Counting DO-Loop
There are two forms of loops, the counting loop and the general loop. The syntax of the counting loop is the following:
where control-var is an INTEGER variable, initial-value and final-value are two INTEGER expressions, and step-size is
also an INTEGER expression whose value cannot be zero. Note that step-size is optional. If it is omitted, the default value
is 1. statements is a sequence of statements and is usually referred to as the body of the DO-loop. You can use any
executable statement within a DO-loop, including IF-THEN-ELSE-END IF and even another DO-loop.
● 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
● Before the DO-loop starts, the values of initial-value, final-value and step-size are computed exactly once. More
precisely, during the course of executing the DO-loop, these values will not be re-computed.
● step-size cannot be zero.
● If the value of step-size is positive (i.e., counting up):
1. The control-var receives the value of initial-value
2. If the value of control-var is less than or equal to the value of final-value, the statements part is
executed. Then, the value of step-size is added to the value of control-var. Go back and compare the
values of control-var and final-value.
3. If the value of control-var is greater than the value of final-value, the DO-loop completes and the
statement following END DO is executed.
● If the value of step-size is negative (i.e., counting down):
1. The control-var receives the value of initial-value
2. If the value of control-var is greater than or equal to the value of final-value, the statements part is
executed. Then, the value of step-size is added to the value of control-var. Go back and compare the
values of control-var and final-value.
3. If the value of control-var is less than the value of final-value, the DO-loop completes and the statement
following END DO is executed.
Examples
● In the following, the control-var is Count. It receives -3 before the loop starts. It goes down the loop body and
display the values of Count, Count*Count and Count*Count*Count. Thus, -3, 9, -27 are displayed. Then, 2 is
added to Count changing its value from -3 to -1. Since this new value of Count (=-1) is less than the final-
value, the loop body is executed and displays -1, 1, -1. Then, 2 is added to Count again, changing the value of
Count to 1(=(-1)+2). Since this new value is still less than the final-value, the loop body is executed again. This
time, it will display 1, 1, 1. Then, 2 is added to Count the third time, changing its value to 3. Since 3 is still less
than the final-value, 3, 9, 27 are displayed. After adding 2 to the value of Count the fourth time, the new value
of Count is finally greater than the final-value and the DO-loop completes.
INTEGER :: Count
DO Count = -3, 4, 2
WRITE(*,*) Count, Count*Count, Count*Count*Count
END DO
● In the following, since steps-size is omitted, it is assumed to be 1. Therefore, the control-var Iteration receives
3, 4, and 5 in this order.
● 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
In addition to repeatedly processing some data as shown above, the DO-loop has some other uses as presented in the
following examples:
● Adding numbers: Suppose the value of INTEGER variable Number has been given elsewhere, perhaps with a
READ. The following code reads in Number integers and computes their sum into variable Sum.
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.
● Factorial: A simple variation could be used to compute the factorial of a positive integer. The factorial of an
integer N, written as N!, is defined to be the product of 1, 2, 3, ..., N-1, and N. More precisely, N! = N*(N-1)*
(N-2)*...*3*2*1.
INTEGER :: Factorial, N, I
Factorial = 1
DO I = 1, N
Factorial = factorial * I
END DO
In the above, the DO-loop iterates N times. The first iteration multiplies Factorial with 1, the second iteration
multiplies Factorial with 2, the third time with 3, ..., the i-th time with I and so on. Therefore, the values that
are multiplied with the initial value of Factorial are 1, 2, 3, ..., N. At the end of the DO, the value of Factorial
is 1*2*3*...*(N-1)*N.
INTEGER :: count
DO count = -3, 4, 0
...
END DO
● Do not change the value of the control-var. The following is not a good practice:
INTEGER :: a, b, c
DO a = b, c, 3
READ(*,*) a ! the value of a is changed
a = b-c ! the value of a is changed
END DO
● Do not change the value of any variable involved in initial-value, final-value and step-size. The following is not
a good practice:
INTEGER :: a, b, c, d, e
● 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
If the data shown above is stored in a file, say data.in and the above program is compiled to an executable count, then
executing
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
This program uses the same format of input as discussed in previous example. More precisely, the first line gives the
number of data items, followed by that number of input line on each which is a data value. Except for the first input value,
which gives the number of input, all other values are real numbers.
5
1.0
2.0
3.0
4.0
5.0
it will generate the following output. In this input, all data values are positive and none of them is ignored.
6
1.0
2.0
3.0
-4.0
5.0
6.0
● 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
END DO
WRITE(*,*) N, '! = ', Answer
END IF
● 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! -->
15
15! = 2004310016
Discussion
The basics of writing a factorial computation program has been discussed in a factorial example of counting DO.
The general DO-loop is actually very simple. But, to use it properly, you need to be very careful, since it may never stop.
The general DO-loop has a form as follows:
DO
statements
END DO
Between DO and END DO, there are statements. These statements are executed over and over without any chance to get
out of the DO-loop. Here is an example,
REAL :: x, y, z
DO
READ(*,*) x
y = x*x
z = x*x*x
WRITE(*,*) x, ' square = ', y, ' cube = ', z
END DO
One iteration of this loop consists of reading a value for x, computing its square and cube to y and z, respectively, and
displaying the results. Then, the execution goes back to the top and executes the four statements again. Consequently, this
loop is executed over and over and has no chance to stop at all. A loop that never stops is usually referred to as an infinite
loop. To stop the iteration of a DO-loop, we need something else.
The EXIT is as simple as writing down the word EXIT. It is used to bail out the containing loop.
DO
statements-1
EXIT
statements-2
END DO
In the above, statements-1 is executed followed by the EXIT statement. Once the EXIT statement is reached, the control
leaves the inner-most DO-loop that contains the EXIT statement. Therefore, in the above case, statements-2 will never be
executed.
Since it must be some reason for bailing out a DO-loop, the EXIT statement is usually used with an IF or even an IF-
THEN-ELSE-END IF statement in one of the following forms. Note that these are not the only cases in which you can use
EXIT.
DO
statements-1
IF (logical-expression) EXIT
statements-2
END DO
DO
statements-1
IF (logical-expression) THEN
statements-THEN
EXIT
END IF
statements-2
END DO
For each iteration, statements in statements-1 are executed, followed the evaluation of the logical-expression. If the result
is .FALSE., statements in statements-2 are executed. This completes one iteration and the control goes back to the top and
executes statements-1 again for next iteration.
If the result of evaluating logical-expression is .TRUE., the first form will executes EXIT, which immediately stops the
execution of the DO-loop. The next statement to be executed is the one following END DO.
For the second form, if the result of evaluating logical-expression is .TRUE., statements in statements-THEN are
executed followed by the EXIT statement, which brings the execution to the statement following END DO.
Therefore, statements in statements-THEN will do some "house-keeping" work before leaving the DO-loop. If there
is no "house-keeping" work, the first form will suffice.
Examples
● The following code reads in values into variable x until the input value becomes negative. All input values are
added to Sum. Note that the negative one is not added to Sum, since once the code sees such a negative value,
EXIT is executed.
INTEGER :: x, Sum
Sum = 0
DO
READ(*,*) x
IF (x < 0) EXIT
Sum = Sum + x
END DO
● The following is an example that "simulates" a counting DO-loop using REAL variables. Variable x is
initialized to the initial value Lower and serves as a control variable. Before any statement of the DO-loop is
executed, the value of x is checked to see if it is greater than the final value Upper. If it is, EXIT is executed,
leaving the loop. Otherwise, the loop body is executed and before goes back to the top, the control variable x
must be increased by the step size Step. This loop will display -1.0, -0.75, -0.5, -0.25, 0.0, 0.25, 0.5, 0.75 and 1.0,
each of them is on a separate line.
REAL :: x
● In many cases, your program may expect an input satisfying certain conditions. DO-loop can help a lot. The
following code keeps asking and checking if the input integer value is in the range of 0 and 10 inclusive. If it is
not, the program warns the user and reads again until the input is in the stated range.
INTEGER :: Input
DO
WRITE(*,*) 'Type an integer in the range of 0 and 10 please --> '
READ(*,*) Input
IF (0 <= Input .AND. Input <= 10) EXIT
WRITE(*,*) 'Your input is out of range. Try again'
END DO
● One of the most commonly seen problem is forgetting to change the logical-expression that may cause an
EXIT. The following DO-loop never stops and keeps displaying 5, 5, 5, 5, ..., forever. The reason? The value of
i is never changed.
INTEGER :: i
i = 5
DO
IF (i < -2) EXIT
WRITE(*,*) i
END DO
INTEGER :: i = 1, j = 5
DO
IF (j < 0) EXIT
WRITE(*,*) i
i = i + 1
END DO
● Sometimes we just forget to initialize the control-var . We really do not know what would be displayed since
the value of i is unknown at the beginning of the DO and is certainly unknown after executing i = i - 1.
INTEGER :: i
DO
IF (i <= 3) EXIT
WRITE(*,*) i
i = i - 1
END DO
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
END IF
END DO
WRITE(*,*)
IF (Count > 0) THEN ! if at one data item found
WRITE(*,*) 'Found ', Count, ' data items'
WRITE(*,*) ' Maximum = ', Maximum
WRITE(*,*) ' Minimum = ', Minimum
ELSE
WRITE(*,*) 'No data item found.' ! no data item found
END IF
If this program uses the input shown at the beginning, it will generate the following output:
Data item #1 = 5
Data item #2 = 3
Data item #3 = 9
Data item #4 = 2
Data item #5 = 7
Data item #6 = 4
Discussion
● The data reading scheme is easy and will not be discussed. It has been discussed in an example of general DO.
● Variable Count is used for counting the number of data items.
● Once a non-negative item is read in, the value of Count is increased by 1 and the input value is displayed.
● If this is the first value (i.e., Count being 1), it is the maximum and the minimum value we have seen so far.
Therefore, the value of Input is saved in Minimum and Maximum which hold the minimum and maximum values
seen so far.
● If it is not the first input value, then Input is compared against Minimum and Maximum. If Input is less than
Minimum, then the new value is less than the minimum so far and should become the new minimum. Likewise, if
Input is greater than Maximum, then the new value is greater than the maximum so far and should become the new
maximum. These activities are handled in the ELSE part.
● After all input are read, Count should be checked again to see if there is any input value at all. If there are, the count,
minimum and maximum are displayed; otherwise, a message is displayed.
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
If the input are 10.0 for b and 0.00001 for the tolerance, the following output shows that it requires 6 iterations to reach an
approximation of square root of 10. Comparing the result with the one obtained from Fortran intrinsic function SQRT(), the
absolute error is zero.
After 6 iterations:
The estimated square root is 3.1622777
The square root from SQRT() is 3.1622777
Absolute error = 0.E+0
If the input are 0.5 for b and 0.00001 for the tolerance, it takes 4 iterations to reach an approximation of the square root of
0.5. The value from using Fortran intrinsic function SQRT() is 0.707106769 and again the absolute error is 0.
After 4 iterations:
The estimated square root is 0.707106769
The square root from SQRT() is 0.707106769
Absolute error = 0.E+0
Discussion
● This program uses X to hold the input value for b and uses NewX to hold the new guess value. The initial guess is the
input value.
● From the current guess, using Newton's formula, the new guess is compared as
● Then, the absolute error of X and NewX is computed. If it is less than the tolerance value, EXIT the loop and display
the results. Otherwise, the current guess is replaced with the new guess and go back for the next iteration.
Computing EXP(x)
Problem Statement
The exponential function, EXP(x), is defined to be the sum of the following infinite series:
Write a program that reads in a REAL value and computes EXP() of that value using the series until the absolute value of a
term is less than a tolerance value, say 0.00001.
Solution
! ---------------------------------------------------------
! This program computes exp(x) for an input x using the
! infinite series of exp(x). This program adds the
! terms together until a term is less than a specified
! tolerance value. Thus, two values are required:
! the value for x and a tolerance value. In this program,
! he tolerance value is set to 0.00001 using PARAMETER.
! ---------------------------------------------------------
PROGRAM Exponential
IMPLICIT NONE
READ(*,*) X ! read in x
Count = 1 ! the first term is 1 and counted
Sum = 1.0 ! thus, the sum starts with 1
Term = X ! the second term is x
DO ! for each term
IF (ABS(Term) < Tolerance) EXIT ! if too small, exit
Sum = Sum + Term ! otherwise, add to sum
Count = Count + 1 ! count indicates the next term
Term = Term * (X / Count) ! compute the value of next term
END DO
If the input value is 10.0, the following output shows that it requires 35 iterations to reach EXP(10.0)=22026.4648.
Comparing the result with the one obtained from Fortran intrinsic function EXP(), the absolute error is zero.
After 35 iterations:
Exp(10.) = 22026.4648
From EXP() = 22026.4648
Abs(Error) = 0.E+0
If the input is -5.0, it takes 21 iterations to reach EXP(-5.0)=6.744734943E-3. The value from using Fortran intrinsic function
is 6.737946998E-3 and the absolute error is 6.787944585E-6.
After 21 iterations:
Exp(-5.) = 6.744734943E-3
From EXP() = 6.737946998E-3
Abs(Error) = 6.787944585E-6
Discussion
● One obvious way of writing this program is computing each term directly using the formula xi/i!. However, this is not
a wise way, since both xi and i! could get very large when x or i is large. One way to overcome this problem is
rewriting the term as follows:
Therefore, the (i+1)-th term is equal to the product of the i-th term and x/(i+1). In the program, variable Term is used
to save the value of the current term and is updated with
● Count indicates which term is under consideration. Its plays the role of i in the infinite series shown above.
● Since the computation starts with the first term, the value of the first term, x, is saved to Term.
● For each iteration, the absolute value of Term is checked to see if it is less than the tolerance value Tolerance. If it is,
the computation is done and EXIT.
● Otherwise, this term is added to Sum and prepare for the next term. Before this, Count is increased by one to point to
the next term and consequently the next term is computed as Term * (X / Count).
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
END DO ! go back
● 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.
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.
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
END IF
END PROGRAM Prime
● 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
46 is NOT a prime
97 is a prime
Discussion
● Since the input is an arbitrary integer, the program first makes sure its value is greater than or equal to 2; otherwise, a
message is displayed.
● If the input is greater than or equal to 2, the program checks if it is actually equal to 2. If it is, just reports "2 is a
prime".
● The next step is screening out all even numbers. Note that 2 has been checked before the control gets to the second
ELSE-IF. If the input is divisible by 2, it is not a prime number.
● If the control can reach here, the input is an odd number greater than or equal to 3. Then, the program uses 3, 5, 7, 9,
11, ... these odd numbers as divisors to divide the input value stored in Number. These divisors are successively
stored in Divisor.
● Of course, these divisors should start with 3; but, the question is when to stop. A naive answer would be "let us try up
to Number-1" This is too slow since Number cannot be evenly divided by Number-1.
A better choice is the square root of Number? Why is this strange value? If Number is divisible by a, then we can
write Number=a*b for some b. If a is less than or equal to b, then a must be smaller than or equal to the square root
of Number.
Therefore, the upper limit of Divisor is the square root of Number. Stated in a slightly different way, it is "the square
of Divisor is less than or equal to Number". This is better since it only uses integer arithmetic, while the one using
square root involves REAL numbers.
● In the DO-loop, the value for Divisor starts with 3. As long as the square of Divisor is less than or equal to Number
and Number is not divisible by Divisor, the iteration continues.
This loop continues until one of the two conditions holds. If Divisor*Divisor > Number holds, then all odd numbers
that are greater than or equal to 3 and less than or equal to the square root of Number have been tried and none of
them can evenly divide Number. Therefore, Number is a prime number.
Nested DO-Loops
Just like an IF-THEN-ELSE-END IF can contain another IF-THEN-ELSE-END IF (see nested IF for the details), a DO-
loop can contain other DO-loops in its body. The body of the contained DO-loop, usually referred to as the nested DO-
loop, must be completely inside the containing DO-loop. Note further that an EXIT statement only brings the control out of
the inner-most DO-loop that contains the EXIT statement.
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
u Values for v
2 1
3 1 2
4 1 2 3
5 1 2 3 4
For each pair of u and v, the inner loop computes a, b and c. Thus, it will generate the following result (please
verify it):
u v a b c
2 1 4 3 5
1 6 8 10
3
2 12 5 13
1 8 15 17
4 2 16 12 20
3 24 7 25
1 10 24 26
2 20 21 29
5
3 30 16 34
4 40 9 41
● It is obvious that the inner DO-loop computes the sum of all integers in the range of 1 and i (i.e., Sum is equal
to 1+2+3+...+i). Since i runs from 1 to 10, the following loop computes ten sums: 1, 1+2, 1+2+3, 1+2+3+4, ...., 1
+2+3+...+9, and 1+2+3+...+9+10.
INTEGER :: i, j, Sum
DO i = 1, 10
Sum = 0
DO j = 1, i
Sum = Sum + j
END DO
WRITE(*,*) Sum
END DO
● The program below uses Newton's method for computing the square root of a positive number. In fact, it
computes the square roots of the numbers 0.1, 0.1, ..., 0.9 and 1.0.
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:
Solution
! ----------------------------------------------------------
! This program computes the average of each student and the
! the average of the class. The input file starts with an
! integer giving the number of classes. For each class, the
! input starts with an integer giving the number of students
! of that class, followed that number of lines on each of
! which there are three scores. This program reads in the
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
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
If the input for Begin, End and Step are -1.0, 1.0 and 0.1, the program would generate the following output.
The first column shows the data values (i.e., -1.0, -0.9, ..., 1.0), the second is the values from using infinite series with a tolerance
value 0.00001, the third column contains the values from Fortran's intrinsic function EXP(), the forth column has the absolute
errors, and the fifth column has the relative errors.
Let S be the sum computed using infinite series and exp(x) be the result from Fortran's intrinsic function. Then, the absolute error
and relative error are defined as follows:
You may find out that the value for X are not -1.0, -0.9, -0.8, ..., 0.0, 0.1, 0.2, ..., 0.9 and 1.0. It contains errors. For example, the
last value should be 1.0 instead of 0.900000155. This is a problem of precision being not high enough. See the KIND attribute in
a later chapter.
Discussion
● For the computation using infinite series, see a previous example for the details.
● Since the data points are Begin, Begin+Step, Begin+2*Step and so on, it is simply a DO-loop as follows:
X = Begin
DO
IF (X > End) EXIT
... compute EXP(X) here ...
X = X + Step
END DO
● Inserting the computation part into the place "... computing EXP(X) here ..." gives the program shown above.
Armstrong Numbers
Problem Statement
An Armstrong number of three digits is an integer such that the sum of the cubes of its digits is equal to the number itself.
For example, 371 is an Armstrong number since 3**3 + 7**3 + 1**3 = 371.
Write a program to find all Armstrong number in the range of 0 and 999.
Solution
! ---------------------------------------------------------------
! This program computes all Armstrong numbers in the range of
! 0 and 999. An Armstrong number is a number such that the sum
! of its digits raised to the third power is equal to the number
! itself. For example, 371 is an Armstrong number, since
! 3**3 + 7**3 + 1**3 = 371.
! ---------------------------------------------------------------
PROGRAM ArmstrongNumber
IMPLICIT NONE
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
The following is the output from the above program. Thus, there are six Armstrong numbers in the range of 0 and 999.
Armstrong number 1: 0
Armstrong number 2: 1
Armstrong number 3: 153
Armstrong number 4: 370
Armstrong number 5: 371
Armstrong number 6: 407
Discussion
● Three-digit numbers are 000, 001, 002, ..., 009, 010, 011, ..., 019, 020, 021, 022, ..., 099, 100, 101, 102, ..., 109,
110, ... 990, 991, ..., 999. As you can see the right-most digits changes faster than the middle one, which in turn is
faster than the left-most one. As the left-most and the middle digits are fixed to 0 and 0, the right-most digit changes
from 0 to 9. Then, the middle one is increased from 0 to 1. In other words, whenever the right-most digit completes a
0 to 9 cycle, the middle digit is increased by one and the right-most digit restart another 0 to 9 cycle. By the same
token, whenever the middle digit completes a 0 to 9 cycle, the left-most digit is increased by 1 and the middle digit
restarts another 0 to 9 cycle.
Therefore, if a, b and c are the left-most, the middle and the right-most digits, the above discussion is formalized
with the following three nested DO-loops:
DO a = 0, 9
DO b = 0, 9
DO c = 0, 9
... the number is abc .....
END DO
END DO
END DO
● Now, in the inner most DO, the number in hand is abc, where a, b and c are the left-most, middle and the right-most
digits. The number itself is of course a*100 + b*10 + c. The sum of the cubes of the digits is a**3 + b**3 + c**3. In
the program, these two are stored in abc and a3b3c3, respectively.
● Finally, if abc and a3b3c3 are equal, we have found an Armstrong number. We can use abc or a3b3c3
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 READis 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, EXITand 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
IF (Divisor > Input) EXIT ! if a factor is too large, exit and done
DO ! try this factor repeatedly
IF (MOD(Input,Divisor) /= 0 .OR. Input == 1) EXIT
Count = Count + 1
WRITE(*,*) 'Factor # ', Count, ': ', Divisor
Input = Input / Divisor ! remove this factor from Input
END DO
Divisor = Divisor + 2 ! move to next odd number
END DO
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
● If the input value is 586390350, the output consists of 10 factors 2, 3, 5, 5, 7, 7, 13, 17, 19 and 19.
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 Divisorcannot evenly divide Inputor Inputis 1, we exit the loop. The former condition states that
Divisoris not a factor of Input, while the latter means Inputis 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 Inputwill have no factors of 2. Then, we can try all odd numbers to
see some of them could be factors.
● To try odd numbers, it is simply the following:
Divisor = 3
DO
It is not difficult to answer, however. If Input does have a composite factor (a composite number is the product of
several prime numbers), say x = a*b, where a is a prime number. Then, before the program can test if x is a factor, a
has been tested since a < x, and the factor a is removed. Consequently, only a possible factor b remains. In other words,
composite number x is never tested and the program will not report any composite factors.
● Let us factorize 586390350 as an example:
1. Factors of 2 are removed first. Removing the first factor of 2 yields 293195175=586390350/2.
2. Since 293195175 is not even, it has no more factors of 2. So, we shall try all odd numbers: 3, 5, 7, 9, 11, ...
3. Removing a factor of 3 yields 97731725=293195175/3.
4. Since 97731725 has no factors of 3, try 5.
5. Removing a factor of 5 yields 19546345=97731725/5.
6. Removing a factor of 5 a second time yields 3909269=19546345/5.
7. Since 3909269 has no factors of 5, try 7.
8. Removing a factor of 7 yields 558467=3909269/7.
9. Removing a second factor of 7 yields 79781=558467/7.
10. Since 79781 has no factors of 7, try 9.
11. Since 79781 has no factors of 9, try 11.
12. Since 79781 has no factors of 11, try 13.
13. Removing a factor of 13 yields 6137=79781/13.
14. Since 6137 has no factor of 13, try 15.
15. Since 6137 has no factor of 15, try 17.
16. Removing a factor of 17 yields 361=6137/17.
17. Since 361 has no factor of 17, try 19.
18. Removing a factor of 19 yields 19=361/19.
19. Removing a second factor of 19 yields 1=19/19.
20. Since the quotient is already 1, stop and all factors have been reported.
You might feel this is not a very efficient method since testing if 9 and 15 are factors are redundant. Yes, you are right;
but, this is already a reasonable complicated program for CS110 and CS201. You could learn more efficient
factorization algorithms in other computer science and/or mathematics courses, since this is an extremely important
topic.
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
The third component of the above READ is IOSTAT= followed by an INTEGER variable. The meaning of this new form
of READ is simple:
After executing the above READ statement, the Fortran compiler will put an integer value into the integer variable
following IOSTAT=, IOstatus above. Based on the value of IOstatus, we have three different situations:
1. If the value of IOstatus is zero, the previous READ was executed flawlessly and all variables have received their
input values. This is the normal case.
2. If the value of IOstatus is positive, the previous READ has encountered some problem. In general, without knowing
the system dependent information, it is impossible to determine what the problem was. However, if hardware and I/
O devices are working, a commonly seen problem would be illegal data. For example, supplying a real number to an
integer variable. If IOstatus is positive, you cannot trust the values of the variables in the READ statement; they
could all contain garbage values, or some of them are fine while the others are garbage.
3. If the value of IOstatus is negative, it means the end of the input has reached. Under this circumstance, some or all
of the variables in the READ may not receive input values.
What is the end of file? How do we generate it? If you prepare your input using a file, when you save it, the system will
generate a special mark, called end-of-file mark, at the end of that file. Therefore, when you read the file and encounter that
special end-of-file mark, the system would know there is no input data after this mark. If you try to read passing this mark,
it is considered as an error.
If you prepare the input using keyboard, hiting the Ctrl-D key would generate the end-of-mark under UNIX. Once you hit
Ctrl-D, the system would consider your input stop at there. If your program tries to read passing this point, this is an error.
However, with IOSTAT=, you can catch this end-of-file mark and do something about it. A commonly seen application is
that let the program to count the number of data items as will be shown in examples below.
Examples
● In the following code, the DO-loop keeps reading in three integer values into variables a, b and c. After executing a
READ, if Reason is greater than zero, something was wrong in the input; if Reason is less than zero, end-of-file has
reached. Only if Reason is zero, one can start normal processing.
INTEGER :: Reason
INTEGER :: a, b, c
DO
READ(*,*,IOSTAT=Reason) a, b, c
IF (Reason > 0) THEN
... something wrong ...
ELSE IF (Reason < 0) THEN
... end of file reached ...
ELSE
... do normal stuff ...
END IF
END DO
● The following code keeps reading an integer at a time and adds them to a variable sum. If io is greater than zero, it
displays 'Check input. Something was wrong'; if io is less than zero, it displays the value of sum. Note that both
cases EXIT the DO-loop since continuing the loop execution makes no sense. Otherwise, the value of x is
meaningful and is added to sum.
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 READis executed, iowould 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
The input consists of a number of real values, one on each line. The program will count the number of input data items and
ignore those illegal ones.
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.
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
● The following loop only displays 1, 2, 4 and 5. If the value of i is 1, 2, 4 or 5, the execution of the loop enters the
ELSE part and displays the value of i. However, if i is 3, since i == 3 is .TRUE., the CYCLE statement is executed,
which brings back to the beginning of the DO-loop starting the next iteration (i.e., the iteration corresponds to i=4).
INTEGER :: i
DO i = 1, 5
IF (i == 3) THEN
CYCLE
ELSE
WRITE(*,*) i
END IF
END DO
● The following code has a DO-loop for processing the input value stored in Range. At the beginning of the loop, the
value of Range is read in and checked. If the value is less than 2, the CYCLE statement brings the control back to
the beginning of the loop to read a new value for Range. This will continue until a value that is greater than or equal
to 2. Then, the logical expression of the IF-THEN-END IF is .FALSE. and consequently the execution continues
with "... process Range ...".
INTEGER :: Range
DO
WRITE(*,*) 'An integer >= 2 please --> '
READ(*,*) Range
IF (Range < 2) THEN
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.
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/funct-module.html8/5/2006 8:09:53 PM
Designing Functions
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.
2. 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.
● 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.
where arg1, arg2, ..., argn are left out. But, the pait of parenthesis must be there.
Semantics
● 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
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, band care 3, 5, and -2, respectively, Sumwill 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 LOGICALassignment. In the following, if a > 0.0is true, .
TRUE.is stored to Positive; otherwise, Positivereceives .FALSE.
REAL, INTENT(IN) :: a
● The following function, LargerRoot, takes three REAL formal arguments and returns a REAL function value. It
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, r1and r2if 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 Factorialis not used in any computation. Instead, a new INTEGERvariable is used for
computing n!. The final value of Ansis stored to Factorialbefore 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 sidein 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 REALor something
else.
● Forget INTENT(IN).
INTEGER :: a, b
Actually, this is notan error. But, without INTENT(IN), our Fortran compiler will not be able to check many
potential errors for you.
● Change the value of a formal argument declared with INTENT(IN).
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 ais declared with INTENT(IN), its value cannot be changed.
● Forget to store a value to the function name.
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 DoSomethingappears in the right-hand side of the second expression. This is a mistake.
Only a special type of functions, RECURSIVEfunctions, 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*bis 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 above expression involves the use of function Average. Since this function has three formal arguments, three values
must be presented to the function. Here, the values are 1.0, 2.0 and 3.0 and the returned value is the average of these three
numbers (i.e., 2.0). The values or expressions used to invoke a function are referred to as actual arguments.
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 INTEGERwhich doe not match with the type of the first
formal argument. Thus, it is incorrect.
● The actual arguments can be constants, variables and even expressions.
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*cand (b+c)/awill 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:
● If an actual argument is an expression, it is evaluated and the result is saved into a temporary location. Then, the
value in this temporary location is passed.
● If an actual argument is a constant, it is considered as an expression. Therefore, its value is saved to a temporary
location and then passed.
● If an actual argument is a variable, its value is taken and passed to the corresponding formal argument.
● If an actual argument is a variable enclosed in a pair of parenthesis like (A), then this is an expression and its value is
evaluated and saved to a temporary location. Then, this value (in the temporary location) is passed.
● For a formal argument declared with INTENT(IN), any attempt to change its value in the function will cause a
compiler error. The meaning of INTENT(IN) is that this formal argument only receives a value from its
corresponding actual argument and its value cannot be changed.
● Based on the previous point, if a formal argument is declared without using INTENT(IN), its value can be changed.
For writing functions, this is not a good practice and consequently all formal arguments should be declared with
INTENT(IN).
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.
Now you have your functions. Where do they go? There are two places for you to add these functions in. They are either
internal or external. This page only describes internal functions. See external subprogram for the details of using
external functions.
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. Note 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
A Important Note
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
There is a direct consequence of Scope Rule 1. Since an entity declared in a function has a scope of that function, this entity
cannot be seen from outside of the function. In the above example, formal argument k and variables f and g are declared
within function Funct1(), they are only "visible" in function Funct1() and are not visible outside of Funct1(). In other
words, since k, f and g are not "visible" from the main program and function Funct2(), they cannot be used in the main
program and function Funct2(). Similarly, the main program and function Funct1() cannot use the formal arguments u and
v and any entity declared in function Funct2().
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
Frequently we may have a local entity whose name is identical to the name of a global entity. To resolve this name conflict,
we need the following new scope rule:
In the program below, the main program declares a variable i, which is global to function Sum(). However, i is also
declared in function Sum(). According to Scope Rule 3 above, these two is are two different entities. More precisely, when
the value of Sum()'s i is changed, this change will not affect the i in the main program and vice versa. This would save us a
lot of time in finding variables with different names.
PROGRAM Scope_3
IMPLICIT NONE
INTEGER :: i, Max = 5
DO i = 1, Max
Write(*,*) Sum(i)
END DO
CONTAINS
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
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.
! ----------------------------------------------------------
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.
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.
! ---------------------------------------------------------------
Discussion
● Function Cm_to_Inch() converts its formal argument cm to inch, which is returned as the function value. Please
note that the constant 0.3937 is defined as a PARAMETER.
● Function Inch_to_Cm() converts its formal argument inch to cm, which is returned as the function value. Please
note that the constant 2.54 is defined as a PARAMETER.
● The main program uses DO-EXIT-END DO to generate 0, 0.5, 1, 1.5, ..., 8, 8.5, 9, 9.5 and 10. For each value,
Cm_to_Inch() and Inch_to_Cm() are called to perform the desired conversion.
Problem Statement
Given a triangle with side lengths a, b and c, its area can be computed using the Heron's formula:
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)
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.
! ---------------------------------------------------------------
! ---------------------------------------------------------------
! 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
0 0
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
● The function that computes the combinatorial coefficient is INTEGER function Cnr(n,r). Since it must compute n!,
r! and (n-r)!, it would be better to write a function to compute the factorial of an integer. In this way, Cnr() would
just use Factorial() three times rather than using three DO-loops. Note that if the condition does not hold, Cnr()
returns -1.
● INTEGER function Factorial() computes the factorial of its formal argument.
● LOGICAL function Test() is very simple. If condition 0 <= r <= n holds, Test receives .TRUE.; otherwise, it
receives .FALSE.
● The main program has a DO-EXIT-END DO. It asks for two integers and indicates that the program will stop if
both values are zeros. Then, Cnr() is used for computing the combinatorial coefficient. If the returned value is
negative, the input values do not meet the condition and an error message is displayed. Otherwise, the combinatorial
coefficient is shown.
● Note that all three functions are internal functions of the main program.
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.
! ---------------------------------------------------------------
If the input values of Begin, End and Step are 0.0, 10.0 and 0.5, the following is the output from the above program.
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.
! --------------------------------------------------------------------
IMPLICIT NONE
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).
❍ 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
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,
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.
! --------------------------------------------------------------------
The following is the output from the above program with correct input:
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
● Then if Fa and Fc have opposite signs, replacing b and Fb with c and Fc, respectively.
● If Fa and Fc have the same sign, then Fc and Fb must have the opposite sign. In this case, a and Fa are replaced
with c and Fc.
● Either way, the original interval [a,b] is replaced with a new one with half length. This process continues until the
absolute value of the function value at c, Fc, is smaller than the given tolerance value. In this case, c is considered a
root of the given equation.
What is a Module?
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
MODULE module-name
IMPLICIT NONE
[specification part]
CONTAINS
[internal-functions]
END MODULE module-name
Short Examples
● 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
● The following module DegreeRadianConversion contains two PARAMETERs, PI and Degree180, and two
functions DegreeToRadian() and RadianToDegree(). The two PARAMETERs are used in the conversion
functions. Note that these parameters are global to the two functions. See scope rules for the details.
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
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 USEis 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 SomeConstantsis:
MODULE SomeConstants
IMPLICIT NONE
REAL, PARAMETER :: PI = 3.1415926
REAL, PARAMETER :: g = 980
INTEGER :: Counter
END MODULE SomeConstants
PROGRAM MainProgram
USE SomeConstants, ONLY: PI, Counter
IMPLICIT NONE
..........
Thus, MainProgramcan use PIand Counterof module SomeConstants; but, MainProgramcannot use g!
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:
For example, if one wants to give a new name to Counterof module SomeConstants, one should write:
Thus, in a program, whenever it uses MyCounter, this program is actually using Counterof module
SomeConstants.
PROGRAM MainProgram
USE SomeConstants, ONLY: PI, MyCounter => Counter
IMPLICIT NONE
..........
END PROGRAM MainProgram
The above example wants to use PIof module SomeConstants. In this case, when program MainProgramuses PI,
it actually uses the PIof module SomeConstants. Program MainProgramalso uses Counterof module
SomeConstants; but, in this case, since there is a renaming, when MainProgramuses MyCounterit actually uses
Counterof 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 MainProgramhas a variable called g, which is the same as PARAMETERgin module
SomeConstants. By renaming gof SomeConstants, MainProgramcan use variable gfor the variable and
GravityConstantfor the PARAMETERgin module SomeConstants.
However, renaming is not a recommended feature. You should avoid using it whenever possible.
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
If you do not want the executable to be called a.out, you can do the following:
In this case, -o main instructs the Fortran compiler to generate an executable main instead of 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:
That is, list those modules that do not use any other modules first, followed by those modules that only use those
listed modules, followed by your main program.
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
or
Note that the order of listing these .o files may be important. Please consult the rules discussed earlier.
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
! --------------------------------------------------------------------
! 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.
! --------------------------------------------------------------------
Fact = Fact * i ! i to n!
END DO
Factorial = Fact
! --------------------------------------------------------------------
! 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
● The computation of combinatorial coefficients has been discussed in an programming example, where functions Cnr
(n,r) and Factorial(k) are internal functions of the main program.
● In this version, functions Factorial(n) and Combinatorial(n,r) are moved to a module called FactorialModule as
internal functions of that module.
● Factorial(n) takes a non-negative integer and returns its factorial.
● Combinatorial(n,r) takes two non-negative integers n and r. If 0 <= r <= n, the combinatorial coefficient C(n,r) is
returned; otherwise, 0 is returned.
● Note that in module FactorialModule, there is no variables global to its internal functions. All internal functions use
their own internal (or local) variables.
● This module does not perform many checks as in a previous programming example. But, it is not difficult to add
these tests.
● After moving the computation functions to a module, the main program becomes simpler. In the beginning, the main
program must USES FactorialModule so that functions Factorial() and Combinatorial() can be accessed from
within the main program.
● The main program reads in values for n and r. If r <= n, the combinatorial coefficient C(n,r) is computed by calling
Combinatorial(n,r); otherwise, the main program computes Combinatorial(r,n).
● If the main program and module FactorialModule are stored in files fact-1p.f90 and fact-m.f90, respectively, then
you can compile them together with the following command:
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
! --------------------------------------------------------------------
! 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
Discussion
respectively, then you can compile them together with the following command:
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
All entities listed in PRIVATE will not be accessible from outside of the module and all entities listed in PUBLIC can be
accessed from outside of the module. All not listed entities, by default, can be accessed from outside of the module.
In the following code segment, since VolumeOfDeathStar, SecretConstant and BlackKnight are listed in a statement,
they can only be used with the module. On the other hand, SkyWalker and Princess are listed in PUBLIC, they can be
accessed from outside of the module. There are entities not listed: function WeaponPower() and DeathStar. By default,
they are public and can be accessed from outside of the 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
Click here to download this module. You also need a main program to test it. This mean program is identical to the one
used in a previous example. If you need it, click here to download a copy.
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
Interface Blocks
All functions you have seen so far are internal functions that are contained in a program or a module. Functions that are not
contained in any program or modules are external functions. A program can use internal functions, external functions and
functions in modules. Moreover, external functions can be in the same file of the program or in several files.
External functions can be considered as program units that are independent of each other. Thus, the only way of
communication among external functions, the main program and modules is through arguments. In other words, from
outside of an external function, it is impossible to use its variables, PARAMETERs and internal functions.
For example, your main program could be in file prog4.f90. Your functions Area() and Test() are in file area.f90 and
functions ReadData() and DisplayResult() are in file InputOutput.f90. In this case, all four functions are external to the
main program. To compile this three-file program, you need the following command:
This will generate a a.out. Or, you can ask the Fortran compiler to generate an executable called prog4 with the following
command:
In addition to compiling these files, there is one more important thing. How does a function or a program know the way of
using a function? A function has a name, some arguments with certain types, and the type of the function value? Without
these information, a function might not be used correctly. To overcome this problem, an interface block is introduced. More
precisely, any external function to be used should be listed in an interface block along with the declaration of its
arguments and their types and the type of the function value.
Note that an external function can be in the file containing the main program or module. As long as that function is not
contained in any program, function, or module, it is external and an interface block is required in any program, function or
module where this function is used.
Syntax
INTERFACE
type FUNCTION name(arg-1, arg-2, ..., arg-n)
type, INTENT(IN) :: arg-1
type, INTENT(IN) :: arg-2
..........
type, INTENT(IN) :: arg-n
END FUNCTION name
An interface block starts with the keyword INTERFACE and ends with END INTERFACE. For each external function to
be used in a program, module or a function, it should have an entry in an interface block. The information that should be
included are
1. the function header that contains the types of the function value, function name, and arguments,
2. the declaration of each argument, and
3. the END FUNCTION statement.
Note that only the types of argument and their INTENT are important. You can use other names for the arguments;
but, it would be a bad practice.
In fact, you can copy these information from that function's declarations to an interface block. For example, if there are two
external functions in a file as follows:
INTERFACE
INTEGER FUNCTION Coin(value)
INTEGER, INTENT(IN) :: value
END FUNCTION Coin
If only function Volume() is used, one can just copy the information of Volume() to interface block as follows:
INTERFACE
REAL FUNCTION Volume(a, b, c)
REAL, INTENT(IN) :: a, b, c
END FUNCTION Volume
END INTERFACE
The answer is simple. Put it after the IMPLICIT NONE statement. Thus, if the main program needs to use external
functions Coin() and Volume(), the following shows the place for the interface block:
PROGRAM CoinVolume
IMPLICIT NONE
INTERFACE
INTEGER FUNCTION Coin(value)
INTEGER, INTENT(IN) :: value
END FUNCTION Coin
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 that uses external functions 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. A version using internal functions can
be found in an earlier page.
Solution
The following solution has the main program and the two conversion functions in the same file. The order of placing these
functions and the main program in the file is unimportant.
! ---------------------------------------------------------------
! 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
INTERFACE
REAL FUNCTION Cm_to_Inch(cm)
REAL, INTENT(IN) :: cm
END FUNCTION Cm_to_Inch
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
! ---------------------------------------------------------------
! 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.
! ---------------------------------------------------------------
Discussion
● External function Cm_to_Inch() converts its formal argument cm to inch, which is returned as the function value.
Please note that the constant 0.3937 is defined to be a PARAMETER.
● External function Inch_to_Cm() converts its formal argument inch to cm, which is returned as the function value.
Please note that the constant 2.54 is defined to be a PARAMETER.
● The main program uses DO-EXIT-END DO to generate 0, 0.5, 1, 1.5, ..., 8, 8.5, 9, 9.5 and 10. For each value,
Cm_to_Inch() and Inch_to_Cm() are called to perform conversion.
● To provide the main program with correct information of the two external functions, the following interface block is
inserted in the beginning of the main program:
INTERFACE
REAL FUNCTION Cm_to_Inch(cm)
REAL, INTENT(IN) :: cm
END FUNCTION Cm_to_Inch
Problem Statement
We have seen Heron's formula for computing triangle area using internal functions. This problem uses the same idea; but
the program should use external functions.
Given a triangle with side lengths a, b and c, its area can be computed using the Heron's formula:
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.
PROGRAM HeronFormula
IMPLICIT NONE
INTERFACE
LOGICAL FUNCTION TriangleTest(a, b, c)
REAL, INTENT(IN) :: a, b, c
END FUNCTION TriangleTest
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
! --------------------------------------------------------------------
! 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
● External 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.
● External REAL function Area is simple and does not require further discussion.
● 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., a message is displayed and loops back asking for a new set of values.
● To provide the main program with all information for using the two external functions, an interface block is inserted
in the beginning:
INTERFACE
LOGICAL FUNCTION TriangleTest(a, b, c)
REAL, INTENT(IN) :: a, b, c
END FUNCTION TriangleTest