You are on page 1of 186

Fortran 90 Tutorial

Dr. C.-K. Shene

Professor
Department of Computer Science
Michigan Technological University

Select the topics you wish to review:

Introduction and Basic Fortran


Selective Execution (IF-THEN-ELSE and SELECT CASE)
Repetitive Execution (DO Loops)
Functions and Modules
Subroutines
One-Dimensional Arrays
Multi-Dimensional Arrays
Formated Input and Output
Some PPT Slides in PDF Format

o Fortran Basics
o Fortran Control Structures
o Fortran Subprograms
o Fortran Arrays

Program Structure
Your program should have the following form:
PROGRAM program-name
IMPLICIT NONE
[specification part]
[execution part]
[subprogram part]
END PROGRAM program-name
Here are some addition notes:

• Contents in [ ] are optional.


• Keyword IMPLICIT NONE must present.
• A program starts with the keyword PROGRAM,
o followed by a program name,
o followed by the IMPLICIT NONE statement,
o followed my some specification statements,
o followed by the execution part,
o followed by a set of internal subprograms,
o followed by the keywords END PROGRAM and the program name.
• For improving readability, your program should add comment lines.

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

• An entire line may be a comment

! This is a comment line


!
PROGRAM TestComment2
.........
! This is a comment line in the middle of a program
.........
END PROGRAM TestComment2

• A blank line is also interpreted as a comment line.

PROGRAM TestComment3
..........
READ(*,*) Count

! The above blank line is a comment line


WRITE(*,*) Count + 2
END PROGRAM TestComment3

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.

A = 174.5 * Year &


+ Count / 100

The above is equivalent to the following


A = 174.5 * Year + Count / 100

Note that & is not part of the statement.

A = 174.5 * Year &


! this is a comment line
+ Count / 100

The above is equivalent to the following, since the comment is ignored by the compiler:

A = 174.5 * Year + Count / 100

• If the first non-blank character of the continuation line is &, continuation is to the first
character after the &:

A = 174.5 + ThisIsALong&
&VariableName * 123.45

is equivalent to
A = 174.5 + ThisIsALongVariableName * 123.45

In this case, there should be no spaces between the last character and the & on the first line.
For example,

A = 174.5 + ThisIsALong &


&VariableName * 123.45

is equivalent to

A = 174.5 + ThisIsALong VariableName * 123.45

Note that there are spaces between ThisIsALong and VariableName. In this way, a token
(name and number) can be split over two lines. However, this is not recommended

FORTRAN ALPHABETS
Fortran only uses the following characters:
• Letters:

A B C D E F G H I J K L M
N O P Q R S T U V W X Y Z
a b c d e f g h i j k l m
n o p q r s t u v w x y z

• Digits:

0 1 2 3 4 5 6 7 8 9

• Special Characters:

space
' " ( ) * + - / : = _
! & $ ; < > % ? , .

FORTRAN CONSTANTS
Constants or more formally literal constants are the tokens used to denote the value of a
particular type. Fortran has five types of constants: integer, real, complex, logical, and
character string.

• Integer Constants: a string of digits with an optional sign:


o Correct Examples: 0, -345, 768, +12345
o Incorrect Examples:
 1,234 : comma is not allowed
 12.0: no decimal point
 --4 and ++3: too many optional signs
 5- and 7+: the optional sign must precede the string of digits
• Real Constants: There are two representations, decimal representation and
exponential representation.
o Decimal Representation: A decimal point must be presented, but no
commas are allowed. A real constant can have an optional sign.
 Correct Examples: 23.45, .123, 123., -0.12, -.12
 Incorrect Examples:
 12,345.95: no comma is allowed
 75: real constant must have a decimal point
 123.5-: the optional sign must precede the number
 $12.34: cannot use dollar sign $
o Exponential Representation: It consists of an integer or a real number in
decimal representation (the mantissa or fractional part), followed by the letter
E or e, followed by an integer (the exponent).
 Correct Examples
 12.3456E2 or 12.3456e2: this is equal to 1234.56
 -3.14E1 or -3.14e1: this is equal to -31.4
 -1.2E-3 or -1.2e-3: this is equal to -0.0012
 12E3 or 12e3: this is equal to 12000.0
 0E0 or 0e0: this is equal to 0.0
 Incorrect Examples
 12.34E1.2: the exponential part must be an integer constant
 12.34-5: there is no exponential sign E or e
• Complex: Will not be covered in this course
• Logical: See Chapter 3
• Character String: Character constants must be enclosed between double quotes or
apostrophes (single quotes).
The content of a string consists of all characters, spaces included, between the single
or quote quotes, while the length of the string is the number of characters of its
content. The content of a string can be zero and in this case it is an empty string
o Correct Examples:
 'John' and "John": content = John and length = 4
 ' ' and " ": content = a single space and length = 1
 'John Dow #2' and "John Dow #2": content = John Dow #2 and
length = 11
 '' and "": content = nothing and length = 0 (empty string)
o Incorrect Examples:
 'you and me: the closing apostrophe is missing
 Hello, world': the opening apostrophe is missing
 '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.

o Correct Examples:
 'What''s this?': content = What's this? and length = 11
 '''''': content = '' and length = 2
o Incorrect Examples:
 'Tech's seminar': the single quote between h and s should be written
twice.

FORTRAN IDENTIFIERS
A Fortran identifier must satisfy the following rules:

• It has no more than 31 characters


• The first character must be a letter,
• The remaining characters, if any, may be letters, digits, or underscores,
• Fortran identifiers are case insensitive. That is, Smith, smith, sMiTh, SMiTH, smitH
are all identical identifiers.
• Correct Examples:
o MTU, MI, John, Count
o I, X
o I1025, a1b2C3, X9900g
o R2_D2, R2D2_, A__
• Incorrect Examples:
o M.T.U.: only letters, digits, and underscores can be used
o R2-D2: same as above
o 6feet: the first character must be a letter
o _System: same as above
• Use meaningful names
o Good names: Total, Rate, length
o Not so good names: ThisIsALongFORTRANname, X321, A_B_012cm,
OPQ
• 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.

FORTRAN VARIABLES AND THEIR TYPES


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:

• INTEGER: the variable is capable of holding an integer


• REAL: the variable is capable of holding a real number
• COMPLEX: the variable is capable of holding a complex number
• LOGICAL: the variable is capable of holding a logical value (i.e., true or false)
• CHARACTER: the variable is capable of holding a character string of certain length

Click here to learn the forms of these values.

Click here to learn more about declaring variables.

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:

• INTEGER : the variables in list can hold integers


• REAL: the variables in list can hold real numbers
• COMPLEX: the variables in list can hold complex numbers
• LOGICAL: the variables in list can hold logical values (i.e., true or false)
• CHARACTER: the variables in list can hold character strings

Types INTEGER and REAL are easy. The following are examples:

• Variables ZIP, Mean and Total are of type INTEGER:


• INTEGER :: ZIP, Mean, Total
• Variables Average, error, sum and ZAP are of type REAL:
• REAL :: Average, error, sum, ZAP

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:

• Use CHARACTER(LEN=i) to declare character variables of length i. For examples,


o Name and Street are character variables that can hold a string of no more
than 15 characters:
o CHARACTER(LEN=15) :: Name, Street
o FirstName, LastName and OtherName are character variables that can
hold a string of no more than 20 characters:
o CHARACTER(LEN=20) :: FirstName, LastName, OtehrName
• Use CHARACTER(i) to declare character variables of length i. That is, there is no LEN=
in the parenthesis. For examples,
o Name and Street are character variables that can hold a string of no more
than 15 characters:
o CHARACTER(15) :: Name, Street
o FirstName, LastName and OtherName are character variables that can
hold a string of no more than 20 characters:
o CHARACTER(20) :: FirstName, LastName, OtehrName
• If a variable can only hold a single character, the length part can be removed. The
following three declarations are all equivalent:
• CHARACTER(LEN=1) :: letter, digit
• CHARACTER(1) :: letter, digit
• CHARACTER :: letter, digit

Here, variables letter and digit can only hold no more than one character.

• If you want to declare character variables of different length with a single statement,
you can attach a length specification, *i, to the right of a variable. In this case, the
corresponding variable will have the indicated length and all other variables are not
affected.
• CHARACTER(LEN=10) :: City, Nation*20, BOX, bug*1

Here, variables City and BOX can hold a string of no more than 10 characters,
Nation can hold a string of no more than 20 characters, and bug can hold only one
character.
• There is one more way of specifying the length of a character variable. If the length
value is replaced with a asterisk *, it means the lengths of the declared variables are
determined elsewhere. In general, this type of declarations is used in subprogram
arguments or in PARAMETER and is refereed to as assumed length specifier.
• CHARACTER(LEN=*) :: Title, Position

Here, the actual lengths of variables Title and Position are unknown and will be
determined elsewhere.

THE PARAMETER ATTRIBUTE


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:
• INTEGER, PARAMETER :: Limit = 30, Max_Count = 100
• In the example below, E is a name for the real value 2.71828, while PI is a name for
the real value 3.141592:
• REAL, PARAMETER :: E = 2.71828, PI = 3.141592
• In the example below, Total and Count are names for 10 and 5, respectively. The
name, Sum, is defined to be the product of the values of Total and Count and hence
Sum is the name for the value 50(=10*5).
• INTEGER, PARAMETER :: Total = 10, Count = 5, Sum = Total*Count
• In the example below, Name is a name for the string 'John' and State is a name for
the string "Utah"
• CHARACTER(LEN=4), PARAMETER :: Name = 'John', State = "Utah"

It is important to know when assigning a name to a string:

o If the string is longer, truncation to the right will happen. In the following case,
since the length of the string "Smith" is 5 while the length of Name is 4, the
string is truncated to the right and the content of Name is "Smit"
o CHARACTER(LEN=4), PARAMETER :: Name = 'Smith'
o If the string is shorter, spaces will be added to the right. Since the string "LA"
is of length 2 while the name City is of length 4, two spaces will be padded to
the right and the content of City becomes "LA "
o CHARACTER(LEN=4), PARAMETER :: City = "LA"
• This is where the assumed length specifier comes in. That is, Fortran allows the
length of character name to be determined by the length of s string. In the example
below, names Name and City are declared to have assumed length. Since the
lengths of 'John' and "LA" are 4 and 2, the length of the names Name and City are
4 and 2, respectively.
• CHARACTER(LEN=*), PARAMETER :: Name = 'John', City = "LA"

VARIABLES INITIALIZATION
A variable can be considered as a box that can hold a single value. However, initially the
content of a variable (or a box) is empty. Therefore, before one can use a variable, it must
receive a value. Do not assume the compiler or computer will put some value, say 0,
into a variable. There are at least three ways to put a value into a variable:

• initializing it when the program is run


• using an assignment statement
• reading a value from keyboard or other device with a READ statement.

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:

• add an equal sign (=) to the right of a variable name


• to the right of the equal sign, write an expression. It is important to note that all
names in the expression must constants or names of constants.

Initializing a variable is only done exactly once when the computer loads your program into
memory for execution. That is, all initializations are done before the program starts its
execution. The use of un-initialized variables may cause unexpected result.

EXAMPLES:

• The following example initializes variables Offset to 0.1, Length to 10.0, and
tolerance to 1.E-7.

REAL :: Offset = 0.1, Length = 10.0, tolerance = 1.E-7

• The following example initializes variables State1 to "MI", State2 to "MN", and
State3 to "MD".

CHARACTER(LEN=2) :: State1 = "MI", State2 = "MN", State3 = "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.

INTEGER, PARAMETER :: Quantity = 10, Amount = 435, Period = 3


INTEGER :: Pay = Quantity*Amount, Received = Period+5

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

INTEGER, PARAMETER :: Quantity = 10, Amount = 435


INTEGER :: Pay = Quantity*Amount, Received = Period+5
INTEGER, PARAMETER :: Period = 3

ARITHMETIC OPERATORS
Fortran has four types of operators: arithmetic, relational, logical, and character. The
following is a table of these operators, including their priority and associativity.

Associativ
Type Operator
ity

** right to left
Arithme
* / left to right
tic
+ - left to right

Relation
< <= > >= == /= none
al

.NOT. right to left

.AND. left to right


Logical
.OR. left to right

.EQV. .NEQV. left to right

SOME USEFUL NOTES:

• 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

Click here for single mode arithmetic expressions

Click here for mixed mode arithmetic expressions

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.

Operato
INTEGER REAL
r

INTEGE mixed
INTEGER
R mode

mixed
REAL REAL
mode

SIMPLE EXAMPLES:

• 1 + 3 is 4
• 1.23 - 0.45 is 0.78
• 3 * 8 is 24
• 6.5/1.25 is 5.2
• 8.4/4.2 is 2.0 rather than 2, since the result must be of REAL type.
• -5**2 is -25
• 12/4 is 3
• 13/4 is 3 rather than 3.25. Since 13/4 is a single mode arithmetic expression and
since all of its operands are of INTEGER type, the result must also be of INTEGER
type. The computer will truncate the mathematical result (3.25) making it an integer.
Therefore, the result is 3.
• 3/5 is 0 rather than 0.6.

RULES FOR EVALUATING EXPRESSIONS

The following are rules of evaluating a more complicated single mode arithmetic expression:

• Expressions are always evaluated from left to right


• If an operator is encountered in the process of evaluation, its priority is compared
with that of the next one:
o if the next one is lower, evaluate the current operator with its operands
o 3 * 5 - 4

In the above expression, in the left to right scan, operator * is encountered


first. Since the the operator - is lower, 3 * 5 is evaluated first transforming the
given expression to 15 - 4. Hence, the result is 11.

o if the next one is equal to the current, the associativity rules are used to
determine which one should be evaluated. For example, if both the current
and the next operators are *, then 3 * 8 * 6 will be evaluated as (3 * 8) * 6.
On the other hand, if the operator is **, A ** B ** C will be evaluated as A **
(B ** C).
o if the next one is higher than the current, the scan should continue with the
next operator. For example, consider the following expression:
o 4 + 5 * 7 ** 3

if the current operator is +, since the next operator * has higher priority, the
scan continues to *. Once the scan arrives at *, since the next operator ** is
higher, 7 ** 3 is evaluated first, transforming the given expression to

4 + 5 * 343

Then, the new expression is scan again. The next operator to be evaluated is
*, followed by +. Thus, the original expression is evaluated as 4 + (5 * (7 **
3)).

MORE COMPLICATED EXAMPLES:

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

• As in mathematics, subexpressions in parenthesis must be evaluated first.

100 + (1 + 250 / 100) ** 3


--> 100 + (1 + [250 / 100]) ** 3
--> 100 + (1 + 2) ** 3
--> 100 + ([1 + 2]) ** 3
--> 100 + 3 ** 3
--> 100 + [3 ** 3]
--> 100 + 27
--> 127

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

1.0 + 2.0 * 3.0 / ( 6.0*6.0 + 5.0*44.0) ** 0.25


--> 1.0 + [2.0 * 3.0] / (6.0*6.0 + 5.0*44.0) ** 0.25
--> 1.0 + 6.0 / (6.0*6.0 + 5.0*55.0) ** 0.25
--> 1.0 + 6.0 / ([6.0*6.0] + 5.0*44.0) ** 0.25
--> 1.0 + 6.0 / (36.0 + 5.0*44.0) ** 0.25
--> 1.0 + 6.0 / (36.0 + [5.0*44.0]) ** 0.25
--> 1.0 + 6.0 / (36.0 + 220.0) ** 0.25
--> 1.0 + 6.0 / ([36.0 + 220.0]) ** 0.25
--> 1.0 + 6.0 / 256.0 ** 0.25
--> 1.0 + 6.0 / [256.0 ** 0.25]
--> 1.0 + 6.0 / 4.0
--> 1.0 + [6.0 / 4.0]
--> 1.0 + 1.5
--> 2.5
Click here to continue with mixed mode arithmetic expressions.

MIXED MODE ARITHMETIC EXPRESSIONS


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.

Operato INTEG REA


r ER L

INTEGE INTEG REA


R ER L
REA
REAL REAL
L

The rules for evaluating mixed mode arithmetic expressions are simple:

• Use the rules for evaluating single mode arithmetic expressions for scanning.
• After locating an operator for evaluation, do the following:
o if the operands of this operator are of the same type, compute the result of
this operator.
o otherwise, one of the operand is an integer while the other is a real number.
In this case, convert the integer to a real (i.e., adding .0 at the end of the
integer operand) and compute the result. Note that since both operands are
real numbers, the result is a real number.
• There is an exception, though. In a**n, where a is a real and n is a positive
integer, the result is computed by multiplying n copies of a. For example, 3.5**3 is
computed as 3.5*3.5*3.5

SIMPLE EXAMPLES:

• 1 + 2.5 is 3.5
• 1/2.0 is 0.5
• 2.0/8 is 0.25
• -3**2.0 is -9.0
• 4.0**(1/2) is first converted to 4.0**0 since 1/2 is a single mode expression whose
result is 0. Then, 4.0**0 is 1.0

AN IMPORTANT NOTE:
In expression a**b where a is REAL, the result is undefined if the value of a is
negative. For example, -4.0**2 is defined with -16.0 as its result, while (-4.0)**2 is
undefined.

MORE COMPLICATED EXAMPLES:


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

• In the following, 25.0 ** 1 is not converted, and 1 / 3 is zero.

25.0 ** 1 / 2 * 3.5 ** (1 / 3)
--> [25.0 ** 1] / 2 * 3.5 ** (1 / 3)
--> 25.0 / 2 * 3.5 ** (1 / 3)
--> 25.0 / {2} * 3.5 ** (1 / 3)
--> 25.0 / 2.0 * 3.5 ** (1 / 3)
--> 12.5 * 3.5 ** (1 / 3)
--> 12.5 * 3.5 ** ([1 / 3])
--> 12.5 * 3.5 ** 0
--> 12.5 * [3.5 ** 0]
--> 12.5 * 1.0
--> 12.5
Click here to continue with single mode arithmetic expressions.

THE ASSIGNMENT STATEMENT


The assignment statement has the following form:

variable = expression
Its purpose is saving the result of the expression to the right of the assignment operator to
the variable on the left. Here are some rules:

• The expression is evaluated first with the rules discussed in the single mode or the
mixed mode expressions pages.
• If the type of the expression is identical to that of the variable, the result is saved in
the variable.
• Otherwise, the result is converted to the type of the variable and saved there.
o If the type of the variable is INTEGER while the type of the result is REAL, the
fractional part, including the decimal point, is removed making it an integer
result.
o If the type of the variable is REAL while the type of the result is INTEGER,
then a decimal point is appended to the integer making it a real number.
• Once the variable receives a new value, the original one disappears and is no more
available.
• CHARACTER assignment follows the rules stated in the discussion of the
PARAMETER attribute.

EXAMPLES:
• The program segment below declares three INTEGER variables. The first assignment
statement saves an integer value to variable Unit. The second saves a real number
100.99 into variable Amount. However, since Amount is an INTEGER variable, the
real value 100.99 is converted to an integer, 100, and saved into Amount. Thus,
after the second assignment completes, variable Amount holds 100. The third
assignment computes the single mode expression, yielding a result 500 = 5*100.
Thus, variable Total receives 500.

INTEGER :: Total, Amount, Unit

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.

REAL, PARAMETER :: PI = 3.1415926


REAL :: Area
INTEGER :: Radius

Radius = 5
Area = (Radius ** 2) * PI

• In the following, Counter is an INTEGER variable initialized to zero.

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!

INTEGER, PARAMETER :: InchToCM = 2.54, factor = 123.45


INTEGER :: X = 15

InchToCM = factor * X

FORTRAN INTRINSIC FUNCTIONS


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:
Functi Arg. Return
Meaning
on Type Type

ABS(x) absolute value of INTEGE INTEGER


R
x
REAL REAL

SQRT(
square root of x REAL REAL
x)

SIN(x) sine of x radian REAL REAL

COS(x) cosine of x radian REAL REAL

tangent of x
TAN(x) REAL REAL
radian

ASIN(x
arc sine of x REAL REAL
)

ACOS(
arc cosine of x REAL REAL
x)

ATAN(
arc tangent of x REAL REAL
x)

EXP(x) exp(x) REAL REAL

natural logarithm
LOG(x) REAL REAL
of x

• Note that all trigonometric functions use radian rather than degree for measuring angles.
For function ATAN(x), x must be in (-PI/2, PI/2). For ASIN(x) and ACOS(x), x must be
in [-1,1].
• Conversion functions:
Arg. Return
Function Meaning
Type Type

INT(x) integer part x REAL INTEGER

NINT(x) nearest integer to x REAL INTEGER

greatest integer less than or


FLOOR(x) REAL INTEGER
equal to x

FRACTION
the fractional part of x REAL REAL
(x)

INTEGE
REAL(x) convert x to REAL REAL
R

• Other functions:
Arg. Return
Function Meaning
Type Type

INTEGE
INTEGER
MAX(x1, maximum of x1, x2, R
x2, ..., xn) ... xn
REAL REAL

INTEGE
INTEGER
MIN(x1, minimum of x1, R
x2, ..., xn) x2, ... xn
REAL REAL

INTEGE
INTEGER
remainder x - R
MOD(x,y)
INT(x/y)*y
REAL REAL

FUNCTIONS IN AN EXPRESSION:

• Functions have higher priority than any arithmetic operators.


• All arguments of a function can be expressions. These expressions are evaluated first
and passed to the function for computing the function value.
• The returned function value is treated as a value in the expression.

AN EXAMPLE:

The example below has three initialized variables A, B and C. The result is computed and saved
into uninitialized variable R.

REAL :: A = 1.0, B = -5.0, C = 6.0


REAL :: R

R = (-B + SQRT(B*B - 4.0*A*C))/(2.0*A)


The following uses brackets to indicated the order of evaluation:

(-B + SQRT(B*B - 4.0*A*C))/(2.0*A)


--> ([-B] + SQRT(B*B - 4.0*A*C))/(2.0*A)
--> (5.0 + SQRT(B*B - 4.0*A*C))/(2.0*A)
--> (5.0 + SQRT([B*B] - 4.0*A*C))/(2.0*A)
--> (5.0 + SQRT(25.0 - 4.0*A*C))/(2.0*A)
--> (5.0 + SQRT(25.0 - [4.0*A]*C))/(2.0*A)
--> (5.0 + SQRT(25.0 - 4.0*C))/(2.0*A)
--> (5.0 + SQRT(25.0 - [4.0*C))/(2.0*A)
--> (5.0 + SQRT(25.0 - 24.0))/(2.0*A)
--> (5.0 SQRT([25.0 - 24.0]))/(2.0*A)
--> (5.0 + SQRT(1.0))/(2.0*A)
--> (5.0 + 1.0)/(2.0*A)
--> ([5.0 + 1.0])/(2.0*A)
--> 6.0/(2.0*A)
--> 6.0/([2.0*A])
--> 6.0/2.0
--> 3.0
Therefore, R receives 3.0.

LISTED-DIRECTED INPUT: THE READ STATEMENT


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 READ statement has the following forms:

READ(*,*) var1, var2, ..., varn


READ(*,*)

The first form starts with READ(*,*), followed by a list of variable names, separated by
commas. The computer will read values from the keyboard successively and puts the value into
the variables. The second form only has READ(*,*), which has a special meaning.

• The following example reads in four values into variables Factor, N, Multiple and
tolerance in this order.
• INTEGER :: Factor, N
• REAL :: Multiple, tolerance

• READ(*,*) Factor, N, Multiple, tolerance
• The following example reads in a string into Title, followed by three real numbers
into Height, Length and Area.
• CHARACTER(LEN=10) :: Title
• REAL :: Height, Length, Area

• READ(*,*) Title, Height, Length, Area

PREPARING INPUT DATA:

Preparing input data is simple. Here are the rules:

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

For the following READ

CHARACTER(LEN=5) :: Name
REAL :: height, length
INTEGER :: count, MaxLength

READ(*,*) Name, height, count, length, MaxLength

The input data may look like the following:


"Smith" 100.0 25 123.579 10000

Note that all input data are on the same line and separated with spaces. After
reading in this line, the contents of the variables are

Name "Smith"
height 100.0
count 25
length 123.579
MaxLength 100000

• Input values can be on several lines. As long as the number of input values and the
number of variables in the corresponding READ agree, the computer will search for
the input values. Thus, the following input should produce the same result. Note that
even blank lines are allowed in input.

"Smith" 100.0

25
123.579
10000

• The execution of a READ always starts searching for input values with a new input
line.

INTEGER :: I, J, K, L, M, N

READ(*,*) I, J
READ(*,*) K, L, M
READ(*,*) N

If the above READ statements are used to read the following input lines,

100 200
300 400 500
600

then I, J, K, L, M and N will receive 100, 200, 300, 400, 500 and 600, respectively.

• Consequently, if the number of input values is larger than the number of variables in
a READ statement, the extra values will be ignored. Consider the following:

INTEGER :: I, J, K, L, M, N

READ(*,*) I, J, K
READ(*,*) L, M, N

If the input lines are

100 200 300 400


500 600 700 800
900
Variables I, J and K receive 100, 200 and 300, respectively. Since the second READ
starts with a new line, L, M and N receive 500, 600 and 700, respectively. 400 on the
first input line is lost. The next READ will 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

If the input lines are

100 200 300


400 500 600
700 800 900

The first READ reads 100 and 200 into P and Q and 300 is lost. The second READ
starts with a new input line, which is the second one. It does not read in anything.
The third READ starts with the third line and reads 700 and 800 into R and S. As a
result, the three input values (i.e., 400, 500 and 600) are all lost. The third value on
the third line, 900, is also lost.

LISTED-DIRECTED OUTPUT: THE WRITE STATEMENT


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 WRITE statement has the following forms:

WRITE(*,*) exp1, exp2, ..., expn


WRITE(*,*)

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.

• The following example displays the values of four variables on screen:

INTEGER :: Factor, N
REAL :: Multiple, tolerance

WRITE(*,*) Factor, N, 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

WRITE(*,*) Title, (Height + Length) * Area


There are some useful rules:

• Each WRITE starts with a new line.


• Consequently, the second form in which the WRITE does not have a list of
expressions just displays a blank line.

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

This example may produce the following result:

Angle = 20.0
Distance = 1350.0

The time to hit target 10 is 27000sec.

The blank line is generated by the third WRITE.

The above example uses assumed length specifier (i.e., LEN=*) and continuation lines
(i.e., symbol &).

• If there are too many results that cannot be fit into a single line, the computer will
display remaining results on the second, the third line and so on.
OUTPUT FORMAT:

There is nothing to worry about the output format. The computer will use the best way to
display the results. In other words, integers and real numbers will be displayed as integers and
real numbers. But, only the content of a string will be displayed. The computer will also
guarantee that all significant digits will be shown so that one does not have to worry how many
positions should be used for displaying a number. The consequence is that displaying a good-
looking table is a challenge. This will be discussed in FORMAT statement.
PROGRAMMING EXAMPLE: THREE PROGRAMMING TRAPS

PROBLEM STATEMENT

The purpose of this program is to show you three common programming traps:

• A**B**C is not equal to (A**B)**C.


• Dividing an integer with another integer always yields an integer result.
• In PARAMETER, assignment statement and READ, strings may be truncated if the
length of the variable at the receiving end is not long enough.

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'

! The exponential trap

WRITE(*,*) "First, the exponential trap:"


WRITE(*,*) A, ' ** ', B, ' ** ', H, ' = ', A**B**H
WRITE(*,*) '( ', A, ' ** ', B, ' ) **', H, ' = ', (A**B)**H
WRITE(*,*) A, ' ** ( ', B, ' ** ', H, ' ) = ', A**(B**H)
WRITE(*,*)

! The integer division trap. Intrinsic function REAL() converts


! an integer to a real number

WRITE(*,*) "Second, the integer division trap:"


WRITE(*,*)
WRITE(*,*) O, ' / ', P, ' = ', O/P
WRITE(*,*) 'REAL( ', O, ' ) / ', P, ' = ', REAL(O)/P
WRITE(*,*) O, ' / REAL( ', P, ' ) = ', O/REAL(P)
WRITE(*,*)

! The string truncation trap

WRITE(*,*) "Third, the string truncation trap:"


WRITE(*,*) 'IS ', M, ' STILL IN ', N, '?'
WRITE(*,*) 'IS ', X, ' STILL IN ', Y, '?'

END PROGRAM Fortran_Traps

Click here to download this program.

PROGRAM OUTPUT
First, the exponential trap:
2 ** 2 ** 3 = 256
( 2 ** 2 ) **3 = 64
2 ** ( 2 ** 3 ) = 256

Second, the integer division trap:

4 / 6 = 0
REAL( 4 ) / 6 = 0.666666687
4 / REAL( 6 ) = 0.666666687

Third, the string truncation trap:


IS Smith STILL IN TEXAS?
IS Smit STILL IN TEXAS ?

DISCUSSION

• All names in this program are aliases of constants.


• Consider the first group. Variables A, B and H are aliases of 2, 2 and 3. The first
WRITE computes A**B**H, which is equivalent to A**(B**H), and the result is
2**(2**3)=256. The second WRITE computes (A**B)**C and the result is
(2**2)**3=64. The third WRITE computes A**(B**H) and the result is
2**(2**3)=256. Thus, it is clear that A**B**H equal to A**(B**H).
• The second group illustrates the problem unique to integer division. Two integer
aliases are involved, namely O and P with values 4 and 6, respectively. The first
WRITE displays O/P and the result is 4/6=0 since it is an integer division. The second
WRITE converts O to real with intrinsic function REAL(). Thus, in computing
REAL(O)/P, the expression is REAL(4)/6, which becomes 4.0/6 and then 4.0/6.0.
Thus, the result is 0.6666667. The third WRITE should give the same result.
• Go back to the top of this program. Alias M and N should have no problem since the
length of the names and the length of the strings agree. Since the length of X is 4
and is shorter than the length of string 'Smith', X only receives the left-most 4
characters. Now take a look at Y. Since the length of Y is longer than the length of
string 'TEXAS', spaces will be appended to the end to fill up to 6 characters. Thus, Y
actually becomes 'TEXAS '. The output should look like the following:
IS Smith STILL IN TEXAS?
IS Smit STILL IN TEXAS ?

On the second line, it is easily seen that the original Smith becomes Smit and the original
TEXAS becomes TEXAS_, where _ indicates a space.

PROGRAMMING EXAMPLE: COMPUTING MEANS

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

REAL :: X = 1.0, Y = 2.0, Z = 3.0


REAL :: ArithMean, GeoMean, HarmMean

WRITE(*,*) 'Data items: ', X, Y, Z


WRITE(*,*)

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)

WRITE(*,*) 'Arithmetic mean = ', ArithMean


WRITE(*,*) 'Geometric mean = ', GeoMean
WRITE(*,*) 'Harmonic Mean = ', HarmMean

END PROGRAM ComputeMeans


Click here to download this program.
PROGRAM OUTPUT
Data items: 1., 2., 3.

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?

PROGRAMMING EXAMPLE: QUADRATIC EQUATION SOLVER

PROBLEM STATEMENT

Given a quadratic equation as follows:

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

! read in the coefficients a, b and c

WRITE(*,*) 'A, B, C Please : '


READ(*,*) a, b, c

! compute the square root of discriminant d

d = SQRT(b*b - 4.0*a*c)

! solve the equation

root1 = (-b + d)/(2.0*a) ! first root


root2 = (-b - d)/(2.0*a) ! second root

! display the results

WRITE(*,*)
WRITE(*,*) 'Roots are ', root1, ' and ', root2

END PROGRAM QuadraticEquation


Click here to download this program.

PROGRAM OUTPUT
A, B, C Please :
1.0 -5.0 3.0

Roots are 4.30277538 and 0.697224379

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

• The WRITE displays a message like this


• 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 Return key.
Then, these values are stored in a, b and c.
• The first assignment statement computes the square root of the discriminant (i.e.,
b*b - 4.0*a*c) and stores it into variable d.
• The roots are computed with the second and third assignments. Note that the
parenthesis surrounding 2.0*a cannot be removed; otherwise, it is equivalent to ((-b
+ d)/2.0)*a, which is wrong.
• The last two WRITE statements display the roots.

PROGRAMMING EXAMPLE: THE LENGTH OF A PARABOLA SEGMENT

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

REAL :: Height, Base, Length


REAL :: temp, t

WRITE(*,*) 'Height of a parabola : '


READ(*,*) Height

WRITE(*,*) 'Base of a parabola : '


READ(*,*) Base

! ... temp and t are two temporary variables

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

END PROGRAM ParabolaLength


Click here to download this program.

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.

PROGRAMMING EXAMPLE: PROJECTILE MOTION

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

and the magnitude of the velocity vector is

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

REAL, PARAMETER :: g = 9.8 ! acceleration due to gravity


REAL, PARAMETER :: PI = 3.1415926 ! you knew this. didn't you

REAL :: Angle ! launch angle in degree


REAL :: Time ! time to flight
REAL :: Theta ! direction at time in degree
REAL :: U ! launch velocity
REAL :: V ! resultant velocity
REAL :: Vx ! horizontal velocity
REAL :: Vy ! vertical velocity
REAL :: X ! horizontal displacement
REAL :: Y ! vertical displacement
READ(*,*) Angle, Time, U

Angle = Angle * PI / 180.0 ! convert to radian


X = U * COS(Angle) * Time
Y = U * SIN(Angle) * Time - g*Time*Time / 2.0
Vx = U * COS(Angle)
Vy = U * SIN(Angle) - g * Time
V = SQRT(Vx*Vx + Vy*Vy)
Theta = ATAN(Vy/Vx) * 180.0 / PI

WRITE(*,*) 'Horizontal displacement : ', X


WRITE(*,*) 'Vertical displacement : ', Y
WRITE(*,*) 'Resultant velocity : ', V
WRITE(*,*) 'Direction (in degree) : ', Theta

END PROGRAM Projectile


Click here to download this program.

PROGRAM OUTPUT
If the input to the program consists of the following three real values:

45.0 6.0 60.0

The program will generate the following output:

Horizontal displacement : 254.558472


Vertical displacement : 78.158432
Resultant velocity : 45.4763107
Direction (in degree) : -21.1030636

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.

CHARACTER OPERATOR AND SUBSTRINGS


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.

Consider the following statements:

CHARACTER(LEN=4) :: John = "John", Sam = "Sam"


CHARACTER(LEN=6) :: Lori = "Lori", Reagan = "Reagan"
CHARACTER(LEN=10) :: Ans1, Ans2, Ans3, Ans4

Ans1 = John // Lori


Ans2 = Sam // Reagon
Ans3 = Reagon // Sam
Ans4 = Lori // Sam

• Variable Ans1 contains a string "JohnLori**", where * denotes a space. These two
spaces come from variable Lori since its content is "Lori**".
• Variable Ans2 contains a string "Sam Reagan". The space in the string comes from
variable Sam since its content is "Sam*", where, as above, * denotes a space.
• Variable Ans3 contains a string "ReaganSam*".
• Variable Ans4 contains a string "Lori**Sam*".

SUBSTRINGS
A consecutive part of a string is called a substring. One can append the extent specifier
at the end of a CHARACTER variable to indicate a substring. An extent specifier has a form
of

( integer-exp1 : integer-exp2 )
It starts with a (, followed by an integer expression, followed by a colon :, followed by
another integer expression, followed by ). The first integer indicates the first position of the
substring, while the second integer indicates the last position of the substring. Therefore,
(3:5) means the substring consists of the third, fourth and fifth characters. If the content of
variable String is "abcdefghijk", then String(3:5) is a string "cde".

If the first integer expression is missing, the value is assumed to be 1. If the second integer
expression is missing, the value is assumed to be the last character of the string. Continue with
the example in previous paragraph. String(:4) is string "abcd". String(2+5:) is string "ghijk".

As a good programming practice, the value of the first integer expression should be greater than
or equal to 1, and the value of the second integer expression should be less than of equal to the
length of the string.

A string variable with an extent specifier can be used on the left-hand side of an assignment. Its
meaning is assigning the string content on the right-hand side into the substring part of the string
variable. Let the content of a string variable LeftHand of length 10 be "1234567890". The
following are a few examples:
• LeftHand(3:5) = "abc": the new content of LeftHand is "12abc67890".
• LeftHand(1:6) = "uvwxyz": the new content of LeftHand is "uvwxyz7890".
• LeftHand(:6) = "uvzxyz": the result is identical to the previous example.
• LeftHand(4:) = "lmnopqr": the new content of LeftHand is "123lmnopqr".
• LeftHand(3:8) = "abc": the new content of LeftHand is "12abc***90", where *
denotes a space. Note that since LeftHand(3:8) consists of 6 character positions
and "abc" has only three characters, the remaining will be filled with spaces.
• LeftHand(4:7) = "lmnopq": the new content of LeftHand is "123lmno890". It is
due to truncation.

EXAMPLE
! ----------------------------------------------------------------
! This program uses DATE_AND_TIME() to retrieve the system date
! and the system time. Then, it converts the date and time
! information to a readable format. This program demonstrates
! the use of concatenation operator // and substring
! ----------------------------------------------------------------

PROGRAM DateTime
IMPLICIT NONE

CHARACTER(LEN = 8) :: DateINFO ! ccyymmdd


CHARACTER(LEN = 4) :: Year, Month*2, Day*2

CHARACTER(LEN = 10) :: TimeINFO, PrettyTime*12 ! hhmmss.sss


CHARACTER(LEN = 2) :: Hour, Minute, Second*6

CALL DATE_AND_TIME(DateINFO, TimeINFO)

! decompose DateINFO into year, month and day.


! DateINFO has a form of ccyymmdd, where cc = century, yy = year
! mm = month and dd = day

Year = DateINFO(1:4)
Month = DateINFO(5:6)
Day = DateINFO(7:8)

WRITE(*,*) 'Date information -> ', DateINFO


WRITE(*,*) ' Year -> ', Year
WRITE(*,*) ' Month -> ', Month
WRITE(*,*) ' Day -> ', Day

! decompose TimeINFO into hour, minute and second.


! TimeINFO has a form of hhmmss.sss, where h = hour, m = minute
! and s = second

Hour = TimeINFO(1:2)
Minute = TimeINFO(3:4)
Second = TimeINFO(5:10)

PrettyTime = Hour // ':' // Minute // ':' // Second

WRITE(*,*)
WRITE(*,*) 'Time Information -> ', TimeINFO
WRITE(*,*) ' Hour -> ', Hour
WRITE(*,*) ' Minite -> ', Minute
WRITE(*,*) ' Second -> ', Second
WRITE(*,*) ' Pretty Time -> ', PrettyTime

! the substring operator can be used on the left-hand side.

PrettyTime = ' '


PrettyTime( :2) = Hour
PrettyTime(3:3) = ':'
PrettyTime(4:5) = Minute
PrettyTime(6:6) = ':'
PrettyTime(7: ) = Second

WRITE(*,*)
WRITE(*,*) ' Pretty Time -> ', PrettyTime

END PROGRAM DateTime


Click here to download this program.

PROGRAM OUTPUT
Date information -> 19970811
Year -> 1997
Month -> 08
Day -> 11

Time Information -> 010717.620


Hour -> 01
Minite -> 07
Second -> 17.620
Pretty Time -> 01:07:17.620

Pretty Time -> 01:07:17.620

DISCUSSION

• Subroutine DATE_AND_TIME() returns the date of time and day information into two
character arguments. The first one, DateINFO, must have a length of at least 8. The
returned value is in the form of ccyymmdd, where cc gives the century, yy the year,
mm the month, and dd the day. If today is August 11, 1997, the call to this
subroutine returns a string of eight characters "19970811"
• The second argument, TimeINFO, will receive a string of 12 characters with a form
of hhmmss.sss, where hh gives the hour value, mm the minute value, and ss.sss
the second value. Thus, if the time this subroutine is called is 1 after 7 minutes and
17.620 seconds, the returned value is "010717.620"

AKHIR PERTEMUAN 1
SELECTIVE EXECUTION

SELECT THE TOPICS YOU WISH TO REVIEW :


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


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.
The following are examples:

• Answer, Condition, Test, Value and Yes_and_No are LOGICAL variables that
can hold either .TRUE. or .FALSE.:

LOGICAL :: Answer, Condition, Test


LOGICAL :: Value, Yes_and_No

• LOGICAL identifiers Answer and Condition are aliases of .TRUE. and .FALSE.,
respectively:

LOGICAL, PARAMETER :: Answer = .TRUE., Condition = .FALSE.

• LOGICAL variables Test and PreTest are initialized to .TRUE. and .FALSE.,
respectively:

LOGICAL :: Test = .TRUE., PreTest = .FALSE.

• LOGICAL variables Cond_1, Cond_2 and Total are assigned with .TRUE.,
.TRUE. and .FALSE., respectively:

LOGICAL :: Cond_1, Cond_2, Total

Cond_1 = .TRUE.
Cond_2 = .TRUE.
Total = .FALSE.
LOGICAL INPUT AND OUTPUT

When using WRITE(*,*) to display a LOGICAL value, Fortran displays .TRUE. and .FALSE.
with T and F, respectively.

When preparing input for READ(*,*), use T and F for .TRUE. and .FALSE., respectively.

RELATIONAL OPERATORS

There are six relational operators:

• < : less than


• <= : less than or equal to
• > : greater than
• >= : greater than or equal to
• == : equal to
• /= : not equal to

Here are important rules:

• Each of these six relational operators takes two operands. These two operands must
both be arithmetic or both be strings. For arithmetic operands, if they are of different
types (i.e., one INTEGER and the other REAL), the INTEGER operand will be
converted to REAL.
• The outcome of a comparison is a LOGICAL value. For example, 5 /= 3 is
.TRUE. and 7 + 3 >= 20 is .FALSE.
• All relational operators have equal priority and are lower than those of
arithmetics operators as shown in the table below:
Associativ
Type Operator
ity

** right to left
Arithme
* / left to right
tic
+ - left to right

Relation < < > > =


/= none
al = = =
• 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,
• 3.0*SQRT(Total)/(Account + Sum) - Sum*Sum >= Total*GNP - b*b

is equivalent to the following:

(3.0*SQRT(Total)/(Account + Sum) - Sum*Sum) >= (Total*GNP - b*b)

• 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

• 3**2 + 4**2 == 5**2 is .TRUE.


• If the values of REAL variables a, b and c are 1.0, 2.0 and 4.0, respectively,
then b*b - 4.0*a*c >= 0.0 is equivalent to 2.0*2.0 - 4.0*1.0*4.0 >= 0.0,
which evaluates to -12.0 >= 0.0. Thus, the result is .FALSE.
• If REAL variables x and y have values 3.0 and 7.0, and INTEGER variables p
and q have values 6 and 2, what is the result of x*x - y*y + 2.0*x*y /= p*q +
p**3 - q**3?

x*x - y*y + 2.0*x*y /= p*q + p**3 - q**3


--> 3.0*3.0 - 7.0*7.0 + 2.0*3.0*7.0 /= 6*2 + 6**3 - 2**3
--> [3.0*3.0] - 7.0*7.0 + 2.0*3.0*7.0 /= 6*2 + 6**3 - 2**3
--> 9.0 - 7.0*7.0 + 2.0*3.0*7.0 /= 6*2 + 6**3 - 2**3
--> 9.0 - [7.0*7.0] + 2.0*3.0*7.0 /= 6*2 + 6**3 - 2**3
--> 9.0 - 49.0 + 2.0*3.0*7.0 /= 6*2 + 6**3 - 2**3
--> [9.0 - 49.0] + 2.0*3.0*7.0 /= 6*2 + 6**3 - 2**3
--> -40.0 + 2.0*3.0*7.0 /= 6*2 + 6**3 - 2**3
--> -40.0 + [2.0*3.0]*7.0 /= 6*2 + 6**3 - 2**3
--> -40.0 + 6.0*7.0 /= 6*2 + 6**3 - 2**3
--> -40.0 + [6.0*7.0] /= 6*2 + 6**3 - 2**3
--> -40.0 + 42.0 /= 6*2 + 6**3 - 2**3
--> [-40.0 + 42.0] /= 6*2 + 6**3 - 2**3
--> 2.0 /= 6*2 + 6**3 - 2**3
--> 2.0 /= [6*2] + 6**3 - 2**3
--> 2.0 /= 12 + 6**3 - 2**3
--> 2.0 /= 12 + [6**3] - 2**3
--> 2.0 /= 12 + 216 - 2**3
--> 2.0 /= [12 + 216] - 2**3
--> 2.0 /= 228 - 2**3
--> 2.0 /= 228 - [2**3]
--> 2.0 /= 228 - 8
--> 2.0 /= [228 - 8]
--> 2.0 /= [220]
--> 2.0 /= 220.0
--> .TRUE.
In the above, please note the left-to-right evaluation order and the type
conversion making 220 to 220.0 before carrying out /=

COMPARING CHARACTER STRINGS


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

0 < 1 < 2 < 3 < 4 < 5 < 6 < 7 < 8 < 9


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.

Here is the method for comparing two strings:

• The comparison always starts at the first character and proceeds from left
to right.
• If the two corresponding characters are equal, then proceed to the next
pair of characters.
• Otherwise, the string containing the smaller character is considered to be
the smaller one. And, the comparison halts.
• During the process comparison, if
o both strings have consumed all of their characters, they are equal
since all of their corresponding characters are equal.
o otherwise, the shorter string is considered to be the smaller one.

EXAMPLES

• Compare "abcdef" and "abcefg"

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:

"abcde" // "xyz" < "abc" // ("dex" // "ijk")


--> ["abcde" // "xyz"] < "abc" // ("dex" // "ijk")
--> "abcdexyz" < "abc" // ("dex" // "ijk")
--> "abcdexyz" < "abc" // (["dex" // "ijk"])
--> "abcdexyz" < "abc" // ("dexijk")
--> "abcdexyz" < "abc" // "dexijk"
--> "abcdexyz" < ["abc" // "dexijk"]
--> "abcdexyz" < "abcdexijk"
--> .FALSE.

LOGICAL OPERATORS AND EXPRESSIONS

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.

These five logical operators are

• .NOT. : logical not


• .AND. : logical and
• .OR. : logical or
• .EQV. : logical equivalence
• .NEQV. : logical not equivalence

The following is a table of these operators, including there priority and associativity.
Associativ
Type Operator
ity

** right to left
Arithme
* / left to right
tic
+ - left to right

Relation < < > > =


/= none
al = = =

.NOT. right to left

.AND. left to right


Logical
.OR. left to right

.EQV. .NEQV. left to right

TRUTH TABLES
The evaluation of logical expressions is determined by truth tables. Let us start with the
.NOT. operator.

Opera
Result
nd

. .
NOT .TRUE. FALSE
. .

. .
FALSE. TRUE.

Note that .NOT. is a unary operator. Therefore, .NOT. a yields .TRUE. (resp., .FALSE.) if the
value of LOGICAL variable a is .FALSE. (resp., .TRUE.).

The following is the truth table of .AND.:


.
.
.AND. TRUE
FALSE
.

. .
.
TRUE FALSE
TRUE.
. .

. . .
FALS FALS FALSE
E. E. .

Therefore, the result of logical expression a .AND. b is .TRUE. if and only if both operands a
and b are .TRUE.. In all other cases, the result is always .FALSE.

The following is the truth table of .OR.:

.
.
.OR. TRUE
FALSE
.

.
. .
TRUE
TRUE. TRUE.
.

. . .
FALS TRUE FALSE
E. . .

Therefore, the result of logical expression a .OR. b is .FALSE. if and only if both operands a
and b are .FALSE.. In all other cases, the result is always .TRUE. In other words, if one of the
two operands of the .OR. operator is .TRUE., the result is .TRUE.

The following is the truth table of .EQV.:

.
.
.EQV. TRUE
FALSE
.

. .
.
TRUE FALSE
TRUE.
. .

. . .
FALS FALS
TRUE.
E. E.

Therefore, the result of logical expression a .EQV. b is .TRUE. if and only if both operands a
and b have the same value (i.e., both are .TRUE. or both are .FALSE.). As mentioned in
relational expressions, relational operators can only compare arithmetic values and cannot be
used to compare logical values. To compare if two logical values are equal, use .EQV.

The following is the truth table of .NEQV.:

. .
.
NEQV TRUE
FALSE
. .

.
. .
FALS
TRUE. TRUE.
E.

. . .
FALS TRUE FALSE
E. . .

Therefore, the result of logical expression a .NEQV. b is .TRUE. if and only if both operands a
and b do not have the same value. As mentioned in relational expressions, relational operators
can only compare arithmetic values and cannot be used to compare logical values. To compare if
two logical values are not equal, use .NEQV. Note that .NEQV is the opposite of .EQV.. Hence,
to test if logical variables x and y have different values, one can use .NOT. (x .EQV. y). Here, if
x and y have the same value, x .EQV. y is .TRUE. and .NOT. (x .EQV. y) is .FALSE. On the
other hand, if x and y have different values, x .EQV. y is .FALSE. and .NOT. (x .EQV. y) is
.TRUE.

PRIORITY
The priority of .NOT. is the highest, followed by .AND., followed by .OR., followed by .EQV.
and .NEQV. Note that .NOT. is right associative, while the other four are left associative.

Here are some examples:

• Let LOGICAL variables Something and Another have values .TRUE. and .FALSE.,
respectively.

.NOT. Something .AND. Another


--> .NOT. .TRUE. .AND. .FALSE.
--> [.NOT. .TRUE.] .AND. .FALSE.
--> .FALSE. .AND. .FALSE.
--> .FALSE.
In the above, since .NOT. has the highest priority, it is evaluated first. Now, look at
the following example:

.NOT. (Something .AND. Another)


--> .NOT. (.TRUE. .AND. .FALSE.)
--> .NOT. ([.TRUE. .AND. .FALSE.])
--> .NOT. .FALSE.
--> .TRUE.

• Let LOGICAL variables a, b and c have values .TRUE., .TRUE. and .FALSE.,
respectively.

.NOT. a .OR. .NOT. b .AND. c


--> .NOT. .TRUE. .OR. .NOT. .TRUE. .AND. .FALSE.
--> [.NOT. .TRUE.] .OR. .NOT. .TRUE. .AND. .FALSE.
--> .FALSE. .OR. .NOT. .TRUE. .AND. .FALSE.
--> .FALSE. .OR. [.NOT. .TRUE.] .AND. .FALSE.
--> .FALSE. .OR. .FALSE. .AND. .FALSE.
--> .FALSE. .OR. [.FALSE. .AND. .FALSE.]
--> .FALSE. .OR. .FALSE.
--> .FALSE.

• Let INTEGER variable n have a value of 4:

n**2 + 1 > 10 .AND. .NOT. n < 3


--> 4**2 + 1 > 10 .AND. .NOT. 4 < 3
--> [4**2] + 1 > 10 .AND. .NOT. 4 < 3
--> 16 + 1 > 10 .AND. .NOT. 4 < 3
--> [16 + 1] > 10 .AND. .NOT. 4 < 3
--> 17 > 10 .AND. .NOT. 4 < 3
--> [17 > 10] .AND. .NOT. 4 < 3
--> .TRUE. .AND. .NOT. 4 < 3
--> .TRUE. .AND. .NOT. [4 < 3]
--> .TRUE. .AND. .NOT. .FALSE
--> .TRUE. .AND. [.NOT. .FALSE]
--> .TRUE. .AND. .TRUE.
--> .TRUE.

Note that the above expression, if you like, can be rewritten with parentheses as
follows:

(n**2 + 1 > 10) .AND. .NOT. (n < 3)

• Let INTEGER variables m, n, x and y have values 3, 5, 4 and 2, respectively:

.NOT. (m > n .AND. x < y) .NEQV. (m <= n .AND. x >= y)


--> .NOT. (3 > 5 .AND. 4 < 2) .NEQV. (3 <= 5 .AND. 4 >= 2)
--> .NOT. ([3 > 5] .AND. 4 < 2) .NEQV. (3 <= 5 .AND. 4 >= 2)
--> .NOT. (.FALSE. .AND. 4 < 2) .NEQV. (3 <= 5 .AND. 4 >= 2)
--> .NOT. (.FALSE. .AND. [4 < 2]) .NEQV. (3 <= 5 .AND. 4 >= 2)
--> .NOT. (.FALSE. .AND. .FALSE.) .NEQV. (3 <= 5 .AND. 4 >= 2)
--> .NOT. ([.FALSE. .AND. .FALSE.]) .NEQV. (3 <= 5 .AND. 4 >= 2)
--> .NOT. (.FALSE.) .NEQV. (3 <= 5 .AND. 4 >= 2)
--> [.NOT. .FALSE.] .NEQV. (3 <= 5 .AND. 4 >= 2)
--> .TRUE. .NEQV. (3 <= 5 .AND. 4 >= 2)
--> .TRUE. .NEQV. ([3 <= 5] .AND. 4 >= 2)
--> .TRUE. .NEQV. (.TRUE. .AND. 4 >= 2)
--> .TRUE. .NEQV. (.TRUE. .AND. [4 >= 2])
--> .TRUE. .NEQV. (.TRUE. .AND. .TRUE.)
--> .TRUE. .NEQV. ([.TRUE. .AND. .TRUE.])
--> .TRUE. .NEQV. (.TRUE.)
--> .TRUE. .NEQV. .TRUE.
--> .FALSE.

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:

LOGICAL :: Result1, Result2, Result3, Result4

Result1 = .NOT. Something .AND. Another


Result2 = .NOT. a .OR. .NOT. b .AND. c
Result3 = (n**2 + 1 > 10) .AND. .NOT. (n < 3)
Result4 = .NOT. (m > n .AND. x < y) .NEQV. (m <= n .AND. x >= y)

Thus, Result1, Result2, Result3 and Results receive .FALSE., .FALSE., .TRUE. and
.FALSE., respectively.

IF-THEN-ELSE-END IF

The most general form of the IF-THEN-ELSE-END IF statement is the following:

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:

• the logical-expression is evaluated, yielding a logical value


• if the result is .TRUE., the statements in statements-1 are executed
• if the result is .FALSE., the statements in statements-2 are executed
• after finish executing statements in statements-1 or statements-2, the statement
following END IF is executed.

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

what you want to do when the logical


expression is .TRUE.
logical-
expression
what you want to do when the logical
expression is .FALSE.

For example, the third example above has the following description:

a is the smaller
number
a <=
b
b is the smaller
number

Although this is an easy example, you will sense its power when you will be dealing with more
complex problems.

IF-THEN-END IF

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:

• the logical-expression is evaluated, yielding a logical value


• if the result is .TRUE., the statements in statements are executed, followed by the
statement following the IF-THEN-END IF statement.
• if the result is .FALSE., the statement following the IF-THEN-END IF is executed. In
other words, if logical-expression is .FALSE., there is no action taken.

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

IF (MOD(Counter, 10) == 0) THEN


WRITE(*,*)
END IF

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:

what you want to do when the logical


logical- expression is .TRUE.
expression
nothing is here!!!

LOGICAL IF

The logical IF is the simplest form. It has the following form:

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:

• the logical-expression is evaluated, yielding a logical value


• if the result is .TRUE., the statement in one-statement is executed, followed by the
statement following the logical IF statement.
• if the result is .FALSE., the statement following the logical IF is executed. In other
words, when logical-expression is .FALSE., there is no action taken.

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

IF (MOD(Counter, 10) == 0) WRITE(*,*)

The following is wrong since the one-statement if a logical IF can not be another
IF statement.

INTEGER :: a, b, c

IF (a < b) IF (b < c) WRITE(*,*) 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.

PROGRAMMING EXAMPLE 1: QUADRATIC EQUATION SOLVER

PROBLEM STATEMENT

Given a quadratic equation as follows:

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 in the coefficients a, b and c

READ(*,*) a, b, c
WRITE(*,*) 'a = ', a
WRITE(*,*) 'b = ', b
WRITE(*,*) 'c = ', c
WRITE(*,*)

! compute the square root of discriminant d

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

END PROGRAM QuadraticEquation


Click here to download this program.

PROGRAM INPUT AND OUTPUT

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

1.0 5.0 2.0

a = 1.
b = 5.
c = 2.
Roots are -0.438447237 and -4.561553

• If the input to the program consists of 1.0, 2.0 and 5.0, we have the following output.
Since the discriminant is b*b - 4.0*a*c = 2.0*2.0 - 4.0*1.0*5.0 = -16.0 < 0.0, the
ELSE part is executed and a message of no real roots is displayed followed the value
of the discriminant.

1.0 2.0 5.0

a = 1.
b = 2.
c = 5.

There is no real roots!


Discriminant = -16.

DISCUSSION
Here is the box trick of this program. Note that information in different parts of the box do
not have to be very precise. As long as it can tell what to do, it would be sufficient.

computes the real


roots
b*b - 4.0*a*c
>= 0.0
there is no real
roots

PROGRAMMING EXAMPLE 2: FINAL MARK COMPUTATION

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

REAL :: Mark1, Mark2 ! the marks of the papers


REAL :: Final ! the final marks
REAL :: ClassRecordMark ! the class record mark

REAL, PARAMETER :: PassLevel = 50.0 ! the pass level

READ(*,*) ClassRecordMark, Mark1, Mark2

Final = (Mark1 + Mark2) / 2.0


IF (Final <= ClassRecordMark) THEN
Final = (Mark1 + Mark2 + ClassRecordMark) / 3.0
END IF

WRITE(*,*) 'Class Record Mark : ', ClassRecordMark


WRITE(*,*) 'Mark 1 : ', Mark1
WRITE(*,*) 'Mark 2 : ', Mark2
WRITE(*,*) 'Final Mark : ', Final

IF (Final >= PassLevel) THEN


WRITE(*,*) 'Pass Status : PASS'
ELSE
WRITE(*,*) 'Pass Status : FAIL'
END IF

END PROGRAM FinalMark


Click here to download this program.

PROGRAM INPUT AND OUTPUT

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

40.0 60.0 43.0

Class Record Mark : 40.


Mark 1 : 60.
Mark 2 : 43.
Final Mark : 51.5
Pass Status : PASS

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

60.0 45.0 43.0

Class Record Mark : 60.


Mark 1 : 45.
Mark 2 : 43.
Final Mark : 49.3333321
Pass Status : FAIL

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.

PROGRAMMING EXAMPLE 3: HERON'S FORMULA FOR COMPUTING TRIANGLE


AREA

PROBLEM STATEMENT

Given a triangle with side lengths a, b and c, its area can be computed using the Heron's formula:

where s is the half of the perimeter length:

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

REAL :: a, b, c ! three sides


REAL :: s ! half of perimeter
REAL :: Area ! triangle area
LOGICAL :: Cond_1, Cond_2 ! two logical conditions

READ(*,*) a, b, c

WRITE(*,*) "a = ", a


WRITE(*,*) "b = ", b
WRITE(*,*) "c = ", c
WRITE(*,*)

Cond_1 = (a > 0.) .AND. (b > 0.) .AND. (c > 0.0)


Cond_2 = (a+b > c) .AND. (a+c > b) .AND. (b+c > a)
IF (Cond_1 .AND. Cond_2) THEN
s = (a + b + c) / 2.0
Area = SQRT(s*(s-a)*(s-b)*(s-c))
WRITE(*,*) "Triangle area = ", Area
ELSE
WRITE(*,*) "ERROR: this is not a triangle!"
END IF

END PROGRAM HeronFormula


Click here to download this program.

PROGRAM INPUT AND OUTPUT

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

3.0 5.0 7.0

a = 3.
b = 5.
c = 7.

Triangle area = 6.49519062

• If the input to the program consists of 3.0, 4.0 and 7.0, we have the following output.
Although all input values are positive, this is not a triangle since the sum of the first
side (3.0) and the second (4.0) is not grater than the third (8.0). The program
generates an error message.
3.0 4.0 8.0

a = 3.
b = 4.
c = 8.

ERROR: this is not a triangle!

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

-1.0 3.0 5.0

a = -1.
b = 3.
c = 5.

ERROR: this is not a triangle!

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.

Here is the box trick of this program.


computes s and its
area
a, b and c form a
triangle
displays an error
message

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.

Let us start testing if x is positive. What we get is the following:

display +
x>
0 one down (i.e., +) two to go (i.e.,
- and 0)

In the lower part, no decision can been reached. What we want to know is finding out is x
is zero or negative (x cannot be positive here since it has been ruled out in the upper
part). To determine whether a - or a 0 should be displayed, one more decision is required:

display -
x<
0 display
0)

Since this is the work for the lower rectangle, let us put it there yielding the following:
display +

display
x>
-
0 x <
0
display
0

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:

x is in the range of 0 and 1.


display x*x
x <=
1
here we have x > 1. display
2*x

Inserting this box into the previous one yields the following final result:

x < display -x
display
x*x
x <=
0
1
display
2*x

Converting to using IF, we have the following:

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:

a has the potential to be the smallest


a<
b since b <= a, b has the potential to be
the smallest

Now we know a possible smallest number. To find the real smallest one, this "possible"
number must be compared against c. If the possible one is a (the upper part), we need to
do the following:

a is the smallest
a<
c since c <= a and b <= a, c is
the smallest

Let us turn to the lower part, where b has the potential to be the smallest. Comparing with
c yields:

b is the smallest
b<
c since c <= b and b <= a, c is
the smallest
Inserting the above two boxes into the first one yields the following complete solution:

the smallest
is a
a <
c
the smallest
is c
a<
b
the smallest
is b
b <
c
the smallest
is c

Converting to the IF version, we have

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.

The following is a possible solution:

IF (x < 0) THEN
WRITE(*,*) -x
ELSE IF (x <= 1) THEN
WRITE(*,*) x*x
ELSE
WRITE(*,*) 2*x
END IF

• Consider the following code segment:

INTEGER :: x
CHARACTER(LEN=1) :: Grade

IF (x < 50) THEN


Grade = 'F'
ELSE IF (x < 60) THEN
Grade = 'D'
ELSE IF (x < 70) THEN
Grade = 'C'
ELSE IF (x < 80) THEN
Grade = 'B'
ELSE
Grade = 'A'
END IF

First, if x is less than 50, 'F' is assigned to Grade. If x is greater than or equal to 50,
the execution continue with the first ELSE IF where x < 60 is tested. If it is .TRUE.,
'D' is assigned to Grade. Note that one can reach the test of x < 60 simply because
the test x < 50 is .FALSE.. Therefore, when reaches x < 60, we are sure that x >=
50 must hold and as a result, Grade receives 'D' if x is greater than or equal to 50
and is less than 60.

By the same token, we know that if x is greater than or equal to 60 and is less than 70,
Grade receives 'C'. If x is greater than or equal to 70 and is less than 80, Grade receives
'B'. Finally, if x is greater than or equal to 80, Grade receives 'A'.

The first and second examples show that IF-THEN-ELSE IF-END IF can save some space
and at the same time make a program more readable. Compare these two solutions with
those using nest IF.

Note also that not all nested IF can be converted to the IF-THEN-ELSE IF-ELSE-END-IF
form. For example, the example of determining the smallest of three numbers cannot be
converted immediately. In general, if all tests (i.e., logical expressions) are mutually exclusive,
then the chance to have a successful conversion is high. Otherwise, rewriting some parts or
combining logical expression can be helpful. Here is one more example:

Let us reconsider the problem of finding the smallest of three given numbers. We know that if a
is the smallest, then it must be smaller than the other two. Moreover, the condition for a number
being the smallest is mutually exclusive. Thus, we have a successful conversion as follows:

IF (a < b .AND. a < c) THEN


Result = a
ELSE IF (b < a .AND. b < c) THEN
Result = b
ELSE
Result = c
END IF

QUADRATIC EQUATION SOLVER - AGAIN

PROBLEM STATEMENT

Given a quadratic equation as follows:


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 in the coefficients a, b and c

READ(*,*) a, b, c
WRITE(*,*) 'a = ', a
WRITE(*,*) 'b = ', b
WRITE(*,*) 'c = ', c
WRITE(*,*)

! compute the discriminant d

d = b*b - 4.0*a*c
IF (d > 0.0) THEN ! distinct roots?
d = SQRT(d)
root1 = (-b + d)/(2.0*a) ! first root
root2 = (-b - d)/(2.0*a) ! second root
WRITE(*,*) 'Roots are ', root1, ' and ', root2
ELSE
IF (d == 0.0) THEN ! repeated roots?
WRITE(*,*) 'The repeated root is ', -b/(2.0*a)
ELSE ! complex roots
WRITE(*,*) 'There is no real roots!'
WRITE(*,*) 'Discriminant = ', d
END IF
END IF

END PROGRAM QuadraticEquation


Click here to download this program.

PROGRAM INPUT AND OUTPUT

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

1.0 5.0 2.0

a = 1.
b = 5.
c = 2.

Roots are -0.438447237 and -4.561553

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

1.0 -10.0 25.0

a = 1.
b = -10.
c = 25.

The repeated root is 5.

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

1.0 2.0 5.0

a = 1.
b = 2.
c = 5.

There is no real roots!


Discriminant = -16.

DISCUSSION
Here is the box trick of this program.
computes the real roots
b*b - 4.0*a*c
> 0.0 repeated root or no real
root

The lower part is not complete yet since we do not know if the equation has a repeated root.
Therefore, one more test is required:

computes the repeated


b*b - 4.0*a*c root
= 0.0
no real root

Inserting this back to the original yields the following final result:

computes the real roots

b*b - 4.0*a*c compute the repeated


> 0.0 b*b - 4.0*a*c root
= 0.0
no real root

This is the logic used in the above program.

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 in the coefficients a, b and c

READ(*,*) a, b, c
WRITE(*,*) 'a = ', a
WRITE(*,*) 'b = ', b
WRITE(*,*) 'c = ', c
WRITE(*,*)
! compute the discriminant d

d = b*b - 4.0*a*c
IF (d > 0.0) THEN ! distinct roots?
d = SQRT(d)
root1 = (-b + d)/(2.0*a) ! first root
root2 = (-b - d)/(2.0*a) ! second root
WRITE(*,*) 'Roots are ', root1, ' and ', root2
ELSE IF (d == 0.0) THEN ! repeated roots?
WRITE(*,*) 'The repeated root is ', -b/(2.0*a)
ELSE ! complex roots
WRITE(*,*) 'There is no real roots!'
WRITE(*,*) 'Discriminant = ', d
END IF

END PROGRAM QuadraticEquation


Click here to download this program.

Its logic is shown below using the box trick.

>
computes the real roots

b*b - 4.0*a*c ? = computes the repeated


0.0 root

>
no real root

QUADRATIC EQUATION SOLVER - REVISITED

PROBLEM STATEMENT

Given a quadratic equation as follows:

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.

This program should handle all cases.

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 in the coefficients a, b and c

READ(*,*) a, b, c
WRITE(*,*) 'a = ', a
WRITE(*,*) 'b = ', b
WRITE(*,*) 'c = ', c
WRITE(*,*)

IF (a == 0.0) THEN ! could be a linear equation


IF (b == 0.0) THEN ! the input becomes c = 0
IF (c == 0.0) THEN ! all numbers are roots
WRITE(*,*) 'All numbers are roots'
ELSE ! unsolvable
WRITE(*,*) 'Unsolvable equation'
END IF
ELSE ! linear equation
WRITE(*,*) 'This is linear equation, root = ', -c/b
END IF
ELSE ! ok, we have a quadratic equation
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

END PROGRAM QuadraticEquation


Click here to download this program.

PROGRAM INPUT AND OUTPUT


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.

0.0 1.0 5.0

a = 0.E+0
b = 1.
c = 5.

This is linear equation, root = -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.

0.0 0.0 0.0

a = 0.E+0
b = 0.E+0
c = 0.E+0

All numbers are roots

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

0.0 0.0 4.0

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.

Let us start with linear equations.

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:

need to know if c is zero


b =
a=0 the equation is linear
0 b*x+c=0

a quadratic equation

If c is zero, then every number is a root and we have:

every number is a root


c =
0 this equation is not
b =
solvable
a=0
0
the equation is linear
b*x+c=0

a quadratic equation

To complete the bottom rectangle, let us take the box from previous example. The final result is:

a=b=0 c = every number is a root


0 0
this equation is not
solvable
the equation is linear
b*x+c=0

> computes the real roots

b*b - computes the repeated


=
4.0*a*c ? 0.0 root

> no real root

The above program is written based on this logic.

SORT THREE NUMBERS

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

IF (a < b) THEN ! a < b here


IF (a < c) THEN ! a < c : a the smallest
IF (b < c) THEN ! b < c : a < b < c
WRITE(*,*) a, b, c
ELSE ! c <= b : a < c <= b
WRITE(*,*) a, c, b
END IF
ELSE ! a >= c : c <= a < b
WRITE(*,*) c, a, b
END IF
ELSE ! b <= a here
IF (b < c) THEN ! b < c : b the smallest
IF (a < c) THEN ! a < c : b <= a < c
WRITE(*,*) b, a, c
ELSE ! a >= c : b < c <= a
WRITE(*,*) b, c, a
END IF
ELSE ! c <= b : c <= b <= a
WRITE(*,*) c, b, a
END IF
END IF

END PROGRAM Order


Click here to download this program.

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.

So, let us start with a:

a may be the
smallest
a<
b
b may be the
smallest

For the upper rectangle, we need to know if a is less than c, while for the lower rectangle we
need to know if b is less than c:

a is the smallest, relation between b and c


a < unknown
c
c <= a < b here, sorted!!!
a<
b
b is the smallest, relation between a and c
b < unknown
c
c <= b <= a here, sorted!!!

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:

a < a < b < a < b < c here,


b c c sorted!!!

a < c <= b here,


sorted

c <= a < b here,


sorted!!!

b <= a < c here,


sorted!!!
a<
c
b< b < c <= a here,
c sorted!!!

c <= b <= a here,


sorted!!!

The above can be simplified a little if you use LOGICAL operators as discussed in nested IF.
Here is the box diagram:

a < b < c
here
a < b and a b <
<c c
a < b <= c
here

b < a < c
here
b < a and b a <
<c c
b < c <= a
here

c < a < b
here
c < a and c a <
<b b
c < b <= a
here

Converting this diagram to IF-THEN-ELSE IF we have the following:

! -------------------------------------------------------
! This program reads in three INTEGERs and displays them
! in ascending order.
! -------------------------------------------------------

PROGRAM Order
IMPLICIT NONE

INTEGER :: a, b, c

READ(*,*) a, b, c
IF (a <= b .AND. a <= c) THEN ! a the smallest
IF (b <= c) THEN ! a <= b <= c
WRITE(*,*) a, b, c
ELSE ! a <= c <= b
WRITE(*,*) a, c, b
END IF
ELSE IF (b <= a .AND. b <= c) THEN ! b the smallest
IF (a <= c) THEN ! b <= a <= c
WRITE(*,*) b, a, c
ELSE ! b <= c <= a
WRITE(*,*) b, c, a
END IF
ELSE ! c the smallest
IF (a <= b) THEN ! c <= a <= b
WRITE(*,*) c, a, b
ELSE ! c <= b <= a
WRITE(*,*) c, b, a
END IF
END IF

END PROGRAM Order

Click here to download this program.

SELECT CASE STATEMENT

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:

SELECT CASE (selector)


CASE (label-list-1)
statements-1
CASE (label-list-2)
statements-2
CASE (label-list-3)
statements-3
.............
CASE (label-list-n)
statements-n
CASE DEFAULT
statements-DEFAULT
END SELECT
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.

• The first form has only one value


• The second form means all values in the range of value-1 and value-2. In this form,
value-1 must be less than value-2.
• The third form means all values that are greater than or equal to value-1
• The fourth form means all values that are less than or equal to value-2

The rule of executing the SELECT CASE statement goes as follows:

• The selector expression is evaluated


• If the result is in label-list-i, then the sequence of statements in statements-i are
executed, followed by the statement following END SELECT
• If the result is not in any one of the label lists, there are two possibilities:
o if CASE DEFAULT is there, then the sequence of statements in statements-
DEFAULT are executed, followed by the statement following END SELECT
o if there is no CASE DEFAULT is not there, the statement following END
SELECT is executed.

There are some notes for writing good Fortran programs:

• The constants listed in label lists must be unique


• CASE DEFAULT is optional. But with a CASE DEFAULT, you are guaranteed that
whatever the selector value, one of the labels will be used. I strongly suggest to add
a CASE DEFAULT in every SELECT CASE statement.
• The place for CASE DEFAULT can be anywhere within a SELECT CASE statement;
however, put it at the end would be more natural.

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

SELECT CASE (Class)


CASE (1)
WRITE(*,*) 'Freshman'
CASE (2)
WRITE(*,*) 'Sophomore'
CASE (3)
WRITE(*,*) 'Junior'
CASE (4)
WRITE(*,*) 'Senior'
CASE DEFAULT
WRITE(*,*) "Hmmmm, I don't know"
END SELECT
WRITE(*,*) 'Done'

• 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

SELECT CASE (Title)


CASE ("DrMD")
DrMD = DrMD + 1
CASE ("PhD")
PhD = PhD + 1
CASE ("MS")
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.

INTEGER :: Number, Sign

SELECT CASE (Number)


CASE ( : -1)
Sign = -1
CASE (0)
Sign = 0
CASE (1 : )
Sign = 1
END SELECT
WRITE(*,*) "Sign = ", Sign

• If the value of c is one of the first ten letters (in lower case), 'One of the first ten
letters' is displayed; if the value of c is one of l, m, n, o, p, u, v, w, x, y, 'One of l,
m, n, o, p, u, v, w, x, y' is displayed; if the value of c is one of z, q, r, s, t, 'One of
z, q, r, s, t' is displayed; and if the value of c is none of the above, 'Other
characters, which may not be letters' is displayed. In the last case, the value of c
could be one of these lower case letters not listed, an upper case letters, a digit, an
operator, or any other character. So, if you only want to handle lower case letters,
this program is incorrect.

CHARACTER(LEN=1) :: c
SELECT CASE (c)
CASE ('a' : 'j')
WRITE(*,*) 'One of the first ten letters'
CASE ('l' : 'p', 'u' : 'y')
WRITE(*,*) 'One of l, m, n, o, p, u, v, w, x, y'
CASE ('z', 'q' : 't')
WRITE(*,*) 'One of z, q, r, s, t'
CASE DEFAULT
WRITE(*,*) 'Other characters, which may not be letters'
END SELECT

• The following program uses the value of Number to determine the value of Range.

INTEGER :: Number, Range

SELECT CASE (Number)


CASE ( : -10, 10 : )
Range = 1
CASE (-5:-3, 6:9)
Range = 2
CASE (-2:2)
Range = 3
CASE (3, 5)
Range = 4
CASE (4)
Range = 5
CASE DEFAULT
Range = 6
END SELECT

Here is the result:

Rang
Number Why?
e

CASE ( : -10,
<= -10 1
10 : )

-9, -8, -7,


6 CASE DEFAULT
-6

CASE (-5:-3,
-5, -4, -3 2
6:9)

-2, -1, 0,
3 CASE (-2:2)
1, 2

3 4 CASE (3, 5)

4 5 CASE (4)
5 4 CASE (3, 5)

CASE (-5:-3,
6, 7, 8, 9 2
6:9)

CASE ( : -10,
>= 10 1
10 : )

PROGRAMMING EXAMPLE 1: LETTER GRADE COMPUTATION

PROBLEM STATEMENT

At the end of a quarter, the average of three marks must be computed. Then, this average is
rounded and used to determine the corresponding letter grade. The letter grades are computed as
follows:

Grad
Range
e

>= 90 A

< 90 and
AB
>= 85

< 85 and
B
>= 80

< 80 and
BC
>= 75

< 75 and
C
>= 70

< 70 and
CD
>= 65

< 65 and
D
>= 60

< 60 F

Write a program to read three marks, compute its average, round the average and use it to
determine the corresponding letter grade.
SOLUTION
! ----------------------------------------------------------
! This program reads three marks, computes their average
! and determines the corresponding letter grade with
! the following table:
!
! A : average >= 90
! AB : 85 <= average < 90
! B : 80 <= average < 84
! BC : 75 <= average < 79
! C : 70 <= average < 74
! CD : 65 <= average < 69
! D : 60 <= average < 64
! F : average < 60
!
! where 'average' is the rounded average of the three
! marks. More precisely, if the average is 78.6, then it
! becomes 79 after rounding; or, if the average is 78.4,
! it becomes 78 after truncating.
! ----------------------------------------------------------

PROGRAM LetterGrade
IMPLICIT NONE

REAL :: Mark1, Mark2, Mark3


REAL :: Average
CHARACTER(LEN=2) :: Grade

READ(*,*) Mark1, Mark2, Mark3


Average = (Mark1 + Mark2 + Mark3) / 3.0

SELECT CASE (NINT(Average)) ! round Average before use


CASE (:59) ! <= 59 -------------> F
Grade = 'F '
CASE (60:64) ! >= 60 and <= 64 ---> D
Grade = 'D '
CASE (65:69) ! >= 65 and <= 69 ---> CD
Grade = 'CD'
CASE (70:74) ! >= 70 and <= 74 ---> C
Grade = 'C '
CASE (75:79) ! >= 75 and <= 79 ---> BC
Grade = 'BC'
CASE (80:84) ! >= 80 and <= 84 ---> B
Grade = 'B '
CASE (85:89) ! >= 84 and <= 89 ---> AB
Grade = 'AB'
CASE DEFAULT ! >= 90 -------------> A
Grade = 'A '
END SELECT

WRITE(*,*) 'First Mark : ', Mark1


WRITE(*,*) 'Second Mark : ', Mark2
WRITE(*,*) 'Third Mark : ', Mark3
WRITE(*,*) 'Average : ', Average
WRITE(*,*) 'Letter Grade : ', Grade
END PROGRAM LetterGrade
Click here to download this program.

PROGRAM INPUT AND OUTPUT

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

97.0 90.0 94.0

First Mark : 97.


Second Mark : 90.
Third Mark : 94.
Average : 93.6666641
Letter Grade : 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.

92.0 85.0 83.0

First Mark : 92.


Second Mark : 85.
Third Mark : 83.
Average : 86.6666641
Letter Grade : 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.

75.0 60.0 45.0

First Mark : 75.


Second Mark : 60.
Third Mark : 45.
Average : 60.
Letter Grade : D

DISCUSSION
This is an easy example and only one place requires further explanation. The concept of
rounding is converting a real number to its nearest integer. Therefore, after rounding, 4.5
and 4.4 become 5 and 4, respectively. Moreover, after rounding, -4.5 and -4.4 become -5
and -4, respectively. The Fortran intrinsic function for rounding is NINT(), which was
discussed in Fortran intrinsic functions.

In the program, REAL variable Average holds the average of the three input marks. To round
the average value to be used in the SELECT CASE statement, NINT(Average) is used. Other
parts are obvious.
PROGRAMMING EXAMPLE 2: CHARACTER TESTING

PROBLEM STATEMENT

This is an extension of an example discussed in SELECT CASE statement. This program reads
in a character and determines if it is a vowel, a consonant, a digit, one of the four arithmetic
operators, a space, or something else (i.e., %, $, @, etc).

SOLUTION
! ------------------------------------------------------------
! This program reads in a single character and determines if
! it is a vowel, a consonant, a digit, one of the four
! arithmetic operators (+, -, * and /), a space, or something
! else. You can do it with IF-THEN-ELSE-END IF statement; but
! SELECT CASE statement provides a cleaner solution.
!
! For character input, you could use the quote characters like
! 'G'
! Or, just type the character. In this case, the first
! character you type will be read.
! ------------------------------------------------------------

PROGRAM CharacterTesting
IMPLICIT NONE

CHARACTER(LEN=1) :: Input

READ(*,*) Input

SELECT CASE (Input)


CASE ('A' : 'Z', 'a' : 'z') ! rule out letters
WRITE(*,*) 'A letter is found : "', Input, '"'
SELECT CASE (Input) ! a vowel ?
CASE ('A', 'E', 'I', 'O', 'U', 'a', 'e', 'i', 'o','u')
WRITE(*,*) 'It is a vowel'
CASE DEFAULT ! it must be a consonant
WRITE(*,*) 'It is a consonant'
END SELECT
CASE ('0' : '9') ! a digit
WRITE(*,*) 'A digit is found : "', Input, '"'
CASE ('+', '-', '*', '/') ! an operator
WRITE(*,*) 'An operator is found : "', Input, '"'
CASE (' ') ! space
WRITE(*,*) 'A space is found : "', Input, '"'
CASE DEFAULT ! something else
WRITE(*,*) 'Something else found : "', Input, '"'
END SELECT

END PROGRAM CharacterTesting


Click here to download this program.

PROGRAM INPUT AND OUTPUT


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 s, the program should report it is a consonant.

A letter is found : "s"


It is a consonant

• If the input character is U, the program should report it is a vowel.

A letter is found : "U"


It is a vowel

• If the input character is 8, the program should report it is a digit.

A digit is found : "8"

• If the input character is +, the program should report it is an operator.

An operator is found : "+"

• If the input character is a space, the program should report it is a space.

A space is found : " "

• If the input character is none of the above, say &, the program should report it is
something else.

Something else found : "&"

DISCUSSION

To be a vowel or a consonant, the input character must be a lower or upper case letter. So,
the first CASE of the outer SELECT CASE singles out all letters. Within the first CASE,
another SELECT CASE is used to separate vowels from consonants. Since a letter is either a
vowel or a consonant, we use the shorter list (i.e., vowels) in the CASE label and let CASE
DEFAULT deal with the longer list of consonants.

AKHIR PERTEMUAN 2
REPETITIVE EXECUTION

SELECT THE TOPICS YOU WISH TO REVIEW :


Repetitive Execution

Counting DO-Loop Programming Examples:

Counting Positive and Negative Input Values

Computing Arithmetic, Geometric and Harmonic Means

Computing Factorial

General DO-Loop with EXIT Programming Examples:

Determining the Minimum and Maximum of Input Data

Computing the Square Root of a Positive Number

Computing EXP(x)

Computing the Greatest Common Divisor of Two Positive Integers

Checking If a Positive Integer Is a Prime Number

Nested DO-Loop Programming Examples:

Computing Classes Averages

Computing a Set of Values of EXP(x)

Armstrong Numbers

Finding All Primes in the Range of 2 and N

Finding all Prime factors of a Positive Integer

Handling End of File: the READ Statement Revisited

Computing Arithmetic, Geometric and Harmonic Means: Revisited

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

Download my course overheads


COUNTING DO-LOOP

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

DO control-var = initial-value, final-value, [step-size]


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

The following are a few simple examples:

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

INTEGER :: Counter, Init, Final, Step

READ(*,*) Init, Final, Step


DO Counter = Init, Final, Step
.....
END DO

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

INTEGER :: i, Lower, Upper

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

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

EXAMPLES

• In the following, the control-var is Count. It receives -3 before the loop


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

INTEGER :: Count

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

• In the following, since steps-size is omitted, it is assumed to be 1.


Therefore, the control-var Iteration receives 3, 4, and 5 in this order.

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


INTEGER :: Iteration

DO Iteration = Init, Final


WRITE(*,*) 'Iteration ', Iteration
END DO

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

INTEGER :: a, b, c
INTEGER :: List
READ(*,*) a, b, c
DO List = MAX(a, b, c), MIN(a, b, c), -2
WRITE(*,*) List
END DO

FREQUENTLY USED LOOP TRICKS


In addition to repeatedly processing some data as shown above, the DO-loop has
some other uses as presented in the following examples:

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

INTEGER :: Count, Number, Sum, Input

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

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

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

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

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

INTEGER :: Count, Number, Sum, Input


REAL :: Average

Sum = 0
DO Count = 1, Number
READ(*,*) Input
Sum = Sum + Input
END DO
Average = REAL(Sum) / Number
The above seems obvious. But, please note the use of the function REAL()
that converts an INTEGER to a REAL. Without this conversion, Sum /Number
is computed as dividing an integer by an integer, yielding an integer result.
Consult singe mode arithmetic expressions for details.

• Factorial: A simple variation could be used to compute the factorial of a


positive integer. The factorial of an integer N, written as N!, is defined to
be the product of 1, 2, 3, ..., N-1, and N. More precisely, N! = N*(N-1)*(N-
2)*...*3*2*1.

INTEGER :: Factorial, N, I

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

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

SOME HELPFUL NOTES


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

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

INTEGER :: count

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

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

INTEGER :: a, b, c

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

• Do not change the value of any variable involved in initial-value, final-value


and step-size. The following is not a good practice:

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

DO a = b+c, c*d, (b+c)/e


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

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

INTEGER :: i

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

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

REAL :: x

DO x = -1.0, 1.0, 0.25


.....
END DO

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

COUNTING POSITIVE AND NEGATIVE INPUT VALUES

PROBLEM STATEMENT

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

The input is organized as follows:

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

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

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

PROGRAM Counting
IMPLICIT NONE

INTEGER :: Positive, Negative


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

Positive = 0 ! # of positive items


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

READ(*,*) TotalNumber ! read in # of items


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

WRITE(*,*) ! display results


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

END PROGRAM Counting


Click here to download this program.

PROGRAM INPUT AND OUTPUT


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

count < data.in


will generate the following output:

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

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

The total of all input is 5

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

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

COMPUTING ARITHMETIC, GEOMETRIC AND HARMONIC MEANS

PROBLEM STATEMENT

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

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

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

PROGRAM ComputingMeans
IMPLICIT NONE

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

Sum = 0.0 ! for the sum


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

READ(*,*) TotalNumber ! read in # of items


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

IF (TotalValid > 0) THEN ! are there valid items?


Arithmetic = Sum / TotalValid ! yes, compute means
Geometric = Product**(1.0/TotalValid)
Harmonic = TotalValid / InverseSum

WRITE(*,*) 'No. of valid items --> ', TotalValid


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

END PROGRAM ComputingMeans


Click here to download this program.

PROGRAM INPUT AND OUTPUT


This program uses the same format of input as discussed in previous example. More
precisely, the first line gives the number of data items, followed by that number of input line
on each which is a data value. Except for the first input value, which gives the number of
input, all other values are real numbers.
• If the input data is
• 5
• 1.0
• 2.0
• 3.0
• 4.0
• 5.0

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

Input item 1 --> 1.


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

No. of valid items --> 5


Arithmetic mean --> 3.
Geometric mean --> 2.6051712
Harmonic mean --> 2.18978071

• In the following input, the fourth value is negative.


• 6
• 1.0
• 2.0
• 3.0
• -4.0
• 5.0
• 6.0

The output is shown below:

Input item 1 --> 1.


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

# of items read --> 6


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

• Now, let us try the following input in which all values are non-positive:
• 4
• -1.0
• -2.0
• 0.0
• -3.0

We shall get the following output. The program correctly detects there is no valid
data values and displays a message.

Input item 1 --> -1.


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

ERROR: none of the input is positive

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

COMPUTING FACTORIAL

PROBLEM STATEMENT

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

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

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

PROGRAM Factorial
IMPLICIT NONE

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

IF (N < 0) THEN ! input error if N < 0


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

END PROGRAM Factorial


Click here to download this program.

PROGRAM INPUT AND OUTPUT

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

This program computes the factorial of


a non-negative integer

What is N in N! -->
-5

ERROR: N must be non-negative


Your input N = -5

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

This program computes the factorial of


a non-negative integer

What is N in N! -->
0

0! = 1

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

This program computes the factorial of


a non-negative integer

What is N in N! -->
5
5! = 120

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

This program computes the factorial of


a non-negative integer

What is N in N! -->
13

13! = 1932053504

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

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

GENERAL DO-LOOP WITH EXIT

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

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

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

THE EXIT STATEMENT


The EXIT is as simple as writing down the word EXIT. It is used to bail out the containing
loop.

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

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

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

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

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

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

EXAMPLES

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

INTEGER :: x, Sum

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

• The following is an example that "simulates" a counting DO-loop using REAL


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

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


REAL :: x

x = Lower ! initialize the control variable (DON'T FORGET)


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

• In many cases, your program may expect an input satisfying certain


conditions. DO-loop can help a lot. The following code keeps asking and
checking if the input integer value is in the range of 0 and 10 inclusive. If it
is not, the program warns the user and reads again until the input is in the
stated range.

INTEGER :: Input

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

SOME HELPFUL NOTES

• One of the most commonly seen problem is forgetting to change the


logical-expression that may cause an EXIT. The following DO-loop never
stops and keeps displaying 5, 5, 5, 5, ..., forever. The reason? The value of i
is never changed.

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

The following is another example:

INTEGER :: i = 1, j = 5

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

• Sometimes we just forget to initialize the control-var . We really do not


know what would be displayed since the value of i is unknown at the
beginning of the DO and is certainly unknown after executing i = i - 1.

INTEGER :: i

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

DETERMINING THE MINIMUM AND MAXIMUM OF INPUT DATA

PROBLEM STATEMENT

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

5
3
9
2
7
4
-1

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

PROGRAM MinMax
IMPLICIT NONE

COMPUTING THE SQUARE ROOT OF A POSITIVE NUMBER

PROBLEM STATEMENT

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

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

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

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

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

PROGRAM SquareRoot
IMPLICIT NONE

REAL :: Input, X, NewX, Tolerance


INTEGER :: Count

READ(*,*) Input, Tolerance

Count = 0 ! count starts with 0


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

WRITE(*,*) 'After ', Count, ' iterations:'


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

END PROGRAM SquareRoot


Click here to download this program.

PROGRAM INPUT AND OUTPUT


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

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

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

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

DISCUSSION

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

COMPUTING EXP(X)

PROBLEM STATEMENT

The exponential function, EXP(x), is defined to be the sum of the following infinite series:
Write a program that reads in a REAL value and computes EXP() of that value using the series
until the absolute value of a term is less than a tolerance value, say 0.00001.

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

PROGRAM Exponential
IMPLICIT NONE

INTEGER :: Count ! # of terms used


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

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

WRITE(*,*) 'After ', Count, ' iterations:'


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

END PROGRAM Exponential


Click here to download this program.

PROGRAM INPUT AND OUTPUT


If the input value is 10.0, the following output shows that it requires 35 iterations to reach
EXP(10.0)=22026.4648. Comparing the result with the one obtained from Fortran intrinsic
function EXP(), the absolute error is zero.

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

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

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

DISCUSSION

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

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

Term = Term * (X / Count)

where Count is the value of i+1.

• Variable Sum is used to accumulate the values of terms.


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

COMPUTING THE GREATEST COMMON DIVISOR OF TWO POSITIVE INTEGERS

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

1. Compute the remainder c of dividing a by b.


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

Write a program that reads in two integers and computes their greatest common divisor.
Note that these two input could be in any order.
SOLUTION
! ---------------------------------------------------------
! This program computes the GCD of two positive integers
! using the Euclid method. Given a and b, a >= b, the
! Euclid method goes as follows: (1) dividing a by b yields
! a reminder c; (2) if c is zero, b is the GCD; (3) if c is
! no zero, b becomes a and c becomes c and go back to
! Step (1). This process will continue until c is zero.
! ---------------------------------------------------------

PROGRAM GreatestCommonDivisor
IMPLICIT NONE

INTEGER :: a, b, c

WRITE(*,*) 'Two positive integers please --> '


READ(*,*) a, b
IF (a < b) THEN ! since a >= b must be true, they
c = a ! are swapped if a < b
a = b
b = c
END IF

DO ! now we have a <= b


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

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

END PROGRAM GreatestCommonDivisor


Click here to download this program.

PROGRAM INPUT AND OUTPUT

• If the input values are 46332 and 71162, the computed GCD is 26.

Two positive integers please -->


46332 71162

The GCD is 26
• If the input values are 128 and 32, the GCD is 32.

Two positive integers please -->


128 32

The GCD is 32

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

Two positive integers please -->


100 101

The GCD is 1

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

The GCD is 97

DISCUSSION

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

would the following change to the WRITE statement work?

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

CHECKING IF A POSITIVE INTEGER IS A PRIME NUMBER

PROBLEM STATEMENT

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

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

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

PROGRAM Prime
IMPLICIT NONE

INTEGER :: Number ! the input number


INTEGER :: Divisor ! the running divisor

READ(*,*) Number ! read in the input


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

PROGRAM INPUT AND OUTPUT

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

Illegal input

• If the input is 2, it is a prime number.

2 is a prime

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

3 is a prime

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


46 is NOT a prime

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

97 is a prime

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

9797 is NOT a prime

DISCUSSION

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

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

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

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

Since Divisor can only be odd numbers, step-size is 2.

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

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


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

NESTED DO-LOOPS

Just like an IF-THEN-ELSE-END IF can contain another IF-THEN-ELSE-END IF (see


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

Suppose we have the following nested DO loops:

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

The following are a few simple examples:

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

INTEGER :: i, j

DO i = 1, 9
DO j = 1, 9
WRITE(*,*) i*j
END DO
END DO
Once this is done, the value of i is advanced to the next one, and the inner
loop will iterate 9 times again displaying the product of the new i and 1, 2,
3,4 ..., 9.

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

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

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

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

The above discussion can be summarized in the following table:

Values for
u
v

21

3 1 2

4 1 2 3

5 1 2 3 4

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

uva b c

21 4 3 5

3 1 6 8 10
2 12 5 13

1 8 15 17

4 2 16 12 20

3 24 7 25

1 10 24 26

2 20 21 29
5
3 30 16 34

4 40 9 41

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

INTEGER :: i, j, Sum

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

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

REAL :: Start = 0.1, End = 1.0, Step = 0.1


REAL :: X, NewX, Value

Value = Start
DO
IF (Value > End) EXIT
X = Value
DO
NewX = 0.5*(X + Value/X)
IF (ABS(X - NewX) < 0.00001) EXIT
X = NewX
EBD DO
WRITE(*,*) 'The square root of ', Value, ' is ', NewX
Value = Value + Step
END DO
Newton's method is taken directly from the programming example, where X
is the current guess, NewX is the new guess, and Value is the number for
square root computation. The EXIT statement brings the execution of the
inner DO to the WRITE statement.

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

REAL :: Start = 0.1, End = 1.0, Step = 0.1


REAL :: X, NewX, Value

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

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

COMPUTING CLASSES AVERAGES

PROBLEM STATEMENT

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

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

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

1. the average of each student;


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

Click here to download this data file.


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

PROGRAM ClassAverage
IMPLICIT NONE

INTEGER :: NoClass ! the no. of classes


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

READ(*,*) NoClass ! read in the # of classes


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

END PROGRAM ClassAverage


Click here to download this program.

PROGRAM INPUT AND OUTPUT


The input shown above should produce the following output:

Class 1 has 3 students

1, 97., 87., 90., 91.3333359


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

Class 2 has 2 students

1, 100., 100., 98., 99.3333359


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

Class 3 has 4 students

1, 78., 75., 90., 81.


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

Class 4 has 3 students

1, 60., 65., 50., 58.3333321


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

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

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

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

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

COMPUTING A SET OF VALUES OF EXP(X)

PROBLEM STATEMENT

In a previous example we have discussed the way of using infinite series for computing the
exponential function EXP(x). The exponential function, EXP(x), is usually defined to be the
sum of the following infinite series:
Write a program that reads in an initial value Begin, a final value End and a step size Step, and
computes the exponential function value at Begin, Begin+Step, Begin+2*Step, ...

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

PROGRAM Exponential
IMPLICIT NONE

INTEGER :: Count ! term count


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

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


READ(*,*) Begin, End, Step

X = Begin ! X starts with the beginning value


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

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

X = X + Step
END DO

END PROGRAM Exponential


Click here to download this program.

PROGRAM INPUT AND OUTPUT


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

Initial, Final and Step please -->


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

Let S be the sum computed using infinite series and exp(x) be the result from Fortran's intrinsic
function. Then, the absolute error and relative error are defined as follows:

You may find out that the value for X are not -1.0, -0.9, -0.8, ..., 0.0, 0.1, 0.2, ..., 0.9 and 1.0. It
contains errors. For example, the last value should be 1.0 instead of 0.900000155. This is a
problem of precision being not high enough. See the KIND attribute in a later chapter.

DISCUSSION

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

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

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

ARMSTRONG NUMBERS

PROBLEM STATEMENT

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

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

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

PROGRAM ArmstrongNumber
IMPLICIT NONE

INTEGER :: a, b, c ! the three digits


INTEGER :: abc, a3b3c3 ! the number and its cubic sum
INTEGER :: Count ! a counter

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

END PROGRAM ArmstrongNumber


Click here to download this program.

PROGRAM INPUT AND OUTPUT


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

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

DISCUSSION

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

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

DO a = 0, 9
DO b = 0, 9
DO c = 0, 9
... the number is abc .....
END DO
END DO
END DO

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

FINDING ALL PRIME NUMBERS IN THE RANGE OF 2 AND N

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

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

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

PROGRAM Primes
IMPLICIT NONE

INTEGER :: Range, Number, Divisor, Count

WRITE(*,*) 'What is the range ? '


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

Count = 1 ! input is correct. start counting


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

Divisor = 3 ! divisor starts with 3


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

IF (Divisor*Divisor > Number) THEN ! are all divisor exhausted?


Count = Count + 1 ! yes, this Number is a prime
WRITE(*,*) 'Prime number #', Count, ': ', Number
END IF
END DO

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

END PROGRAM Primes

Click here to download this program.


PROGRAM INPUT AND OUTPUT

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

What is the range ?


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

Prime number #1: 2


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

There are 3 primes in the range of 2 and 5

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

What is the range ?


100

Prime number #1: 2


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

There are 25 primes in the range of 2 and 100

DISCUSSION

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

WRITE(*,*) 'What is the range ? '


DO
READ(*,*) Range
IF (Range >= 2) EXIT
... incorrect input here ...
END DO

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

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

DO Number = 3, Range, 2
... determine if Number is a prime number ...
... if Number is a prime number, display it ...
END DO

• The segment in the previous example can be used to replace "...determine if Number
is a prime number..." and the final program is the one shown above.

FINDING ALL PRIME FACTORS OF A POSITIVE INTEGER

PROBLEM STATEMENT

As we have learned in high school, any positive integer can be factorized into prime factors. For
example, 586390350 can be factorized as follows:
Thus, 586390350 has factors 2, 3, 5, 5,, 7, 7, 13, 17, 19 and 19. Note that all factors are prime
numbers.

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

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

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

PROGRAM Factorize
IMPLICIT NONE

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

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


READ(*,*) Input

Count = 0
DO ! here, we try to remove all factors of 2
IF (MOD(Input,2) /= 0 .OR. Input == 1) EXIT
Count = Count + 1 ! increase count
WRITE(*,*) 'Factor # ', Count, ': ', 2
Input = Input / 2 ! remove this factor from Input
END DO

Divisor = 3 ! now we only worry about odd factors


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

END PROGRAM Factorize


Click here to download this program.
PROGRAM INPUT AND OUTPUT

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

This program factorizes any integer >= 2 -->


100

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

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

This program factorizes any integer >= 2 -->


16

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

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

This program factorizes any integer >= 2 -->


53

Factor # 1: 53

• If the input value is 586390350, the output consists of 10 factors 2, 3, 5, 5, 7, 7, 13,


17, 19 and 19.

This program factorizes any integer >= 2 -->


586390350

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

DISCUSSION

• How to remove a factor from a given number? I believe you have learned it in high
school. Let the given number be n and we know x is a factor of n. Then, we just keep
dividing n by x until the quotient is 1 or x cannot evenly divide n.
For example, 3 is a factor of 72. The first division yields a quotient 24=72/3. The second
division yields a quotient 8=24/3. Thus, the original number 72 has two factors of 3.

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

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

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

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

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

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

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

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

To try odd numbers, it is simply the following:

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

• Putting everything together, it is the program shown above.


• Why the factors found are prime numbers? A good question, indeed.

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

• Let us factorize 586390350 as an example:


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

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

HANDLING END-OF-FILE: THE READ STATEMENT REVISITED

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

INTEGER :: IOstatus

READ(*,*,IOSTAT=IOstatus) var1, var2, ..., varn


The third component of the above READ is IOSTAT= followed by an INTEGER variable. The
meaning of this new form of READ is simple:
After executing the above READ statement, the Fortran compiler will put an integer value into
the integer variable following IOSTAT=, IOstatus above. Based on the value of IOstatus, we
have three different situations:

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

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

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

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

EXAMPLES

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

INTEGER :: Reason
INTEGER :: a, b, c

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

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

INTEGER :: io, x, sum

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

Now if the input is

1
3
4

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

1
@
3

since @ is not a legal integer, the second time the READ is executed, io would
receive a positive number and the above program exits the DO-loop.

COMPUTING ARITHMETIC, GEOMETRIC AND HARMONIC MEANS: REVISITED

PROBLEM STATEMENT

The arithmetic mean (i.e., average), geometric mean and harmonic mean of a set of n numbers
x1, x2, ..., xn is defined as follows:
Since computing geometric mean requires taking root, it is further required that all input data
values must be positive. As a result, this program must be able to ignore those non-positive
items. However, this may cause all input items ignored. Therefore, before computing the means,
this program should have one more check to see if there are valid items.

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

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

PROGRAM ComputingMeans
IMPLICIT NONE

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

Sum = 0.0
Product = 1.0
InverseSum = 0.0
TotalValid = 0
Count = 0

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

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

WRITE(*,*) '# of items read --> ', Count


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

END PROGRAM ComputingMeans


Click here to download this program.

PROGRAM INPUT AND OUTPUT


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

• If the input data is

1.0
2.0
3.0
4.0
5.0
6.0

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

Input item 1 --> 1.


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

# of items read --> 6


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

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

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

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

Input item 1 --> 1.


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

# of items read --> 10


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

DISCUSSION

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

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

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

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

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

EXAMPLES

• The following loop only displays 1, 2, 4 and 5. If the value of i is 1, 2, 4 or 5, the


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

INTEGER :: i

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

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

INTEGER :: Range

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

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

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

Write a program to find all solutions.

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

PROGRAM Puzzle
IMPLICIT NONE

INTEGER :: R, E, D, F, O, A, N, G ! the digits


INTEGER :: RED, FOR, DANGER ! the constructed values
INTEGER :: Count ! solutions count

WRITE(*,*) 'This program solves the following puzzle:'


WRITE(*,*)
WRITE(*,*) ' RED'
WRITE(*,*) 'x FOR'
WRITE(*,*) '-------'
WRITE(*,*) ' DANGER'
WRITE(*,*)

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

END PROGRAM Puzzle


Click here to download this program.

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

This program solves the following puzzle:

RED
x FOR
-------
DANGER

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

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

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

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

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

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

RED = R*100 + E*10 + D


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

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

Akhir Pertemuan 3

FUNCTIONS AND MODULES

SELECT THE TOPICS YOU WISH TO REVIEW :


Functions and Modules

Designing Functions

Functions Examples

Common Problems
Using Functions

Argument Association

Where Do My Functions Go?

Scope Rules Programming Examples:

Computing Cubes

Computing Means - Revisited

Cm and Inch Conversion

Heron'a Formula for Computing Triangle Area - Revisited

Computing the Combinatorial Coefficient

Computing Square Roots with Newton's Method

Designing a Greatest Common Divisor Function

Finding All Prime Numbers in the Range of 2 and N - Revisited

The Bisection (Bozano) Equation Solver

A Brief Introduction to Modules

What is a Module?

How to Use a Module?

Compile Programs with Modules

Programming Example 1: Factorial and Combinatorial Coefficient

Programming Example 2: Trigonometric Functions Using Degree

A Little Privacy - PUBLIC/PRIVATE

External Functions and Interface Blocks

Interface Blocks

Programming Example 1: Cm and Inch Conversion

Programming Example 2: Heron'a Formula for Computing Triangle Area

Download my course overheads

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:

type FUNCTION function-name (arg1, arg2, ..., argn)


IMPLICIT NONE
[specification part]
[execution part]
[subprogram part]
END FUNCTION function-name

Here are some elaborations of the above syntax:

• The first line of a function starts with the keyword FUNCTION. Before FUNCTION,
the type gives the type of the function value (i.e., INTEGER, REAL, LOGICAL and
CHARACTER) and after FUNCTION is the name you assign to that function.
• Following the function-name, there is a pair of parenthesis in which a number of
arguments arg1, arg2, ..., argn are separated with commas. These arguments are
referred to as formal arguments. Formal arguments must be variable names and
cannot be expressions. Here are a examples:
1. The following is a function called Factorial. It takes only one formal argument
n and returns an INTEGER as its function value.
• INTEGER FUNCTION Factorial(n)
1. The following is a function called TestSomething. It takes three formal
arguments a, b and c, and returns a LOGICAL value (i.e., .TRUE. or .FALSE.)
as its function value.
• LOGICAL FUNCTION TestSomething(a, b, c)
• A function must be ended with END FUNCTION followed by the name of that
function.
• Between FUNCTION and END FUNCTION, there are the IMPLICIT NONE,
specification part, execution part and subprogram part. These are exactly identical to
that of a PROGRAM.

If a function does not need any formal argument, it can be written as


type FUNCTION function-name ()
IMPLICIT NONE
[specification part]
[execution part]
[subprogram part]
END FUNCTION function-name
where arg1, arg2, ..., argn are left out. But, the pait of parenthesis must be there.

SEMANTICS
The meaning of a function is very simple:

• A function is a self-contained unit that receives some "input" from the outside world
via its formal arguments, does some computations, and then returns the result with
the name of the function.
• Thus, since the function returns its result via the name of the function, somewhere in
the function there must exist one or more assignment statements like the following:
• function-name = expression
where the result of expression is stored to the name of the function.

However, the name of the function cannot appear in the right-hand side of any
expression. That is, the name of the function, used as a variable name, can only appear in
the left-hand side of an expression. This is an artificial restriction in this course only.

• A function receives its input values from formal arguments, does computations, and
saves the result in its name. When the control of execution reaches END FUNCTION,
the value stored in the name of the function is returned as the function value.
• To tell the function about the types of its formal arguments, all arguments must be
declared with a new attribute INTENT(IN). The meaning of INTENT(IN) indicates
that the function will only take the value from the formal argument and must not
change its content.
• Any statements that can be used in PROGRAM can also be used in a FUNCTION.

FUNCTIONS EXAMPLES

Here are a few examples of functions:

• 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 FUNCTION Sum(a, b, c)


IMPLICIT NONE

INTEGER, INTENT(IN) :: a, b, c

Sum = a + b + c
END FUNCTION Sum

If the value supplied to a, b and c are 3, 5, and -2, respectively, Sum will receive 6
(=3+5+(-2)) and the function returns 6.

• The following function has a name Positive with a REAL formal argument. If the
argument is positive, the function returns .TRUE.; otherwise, the function returns
.FALSE.

LOGICAL FUNCTION Positive(a)


IMPLICIT NONE

REAL, INTENT(IN) :: a

IF (a > 0.0) THEN


Positive = .TRUE.
ELSE
Positive = .FALSE.
END IF
END FUNCTION Positive

The above function can be made much shorter by using LOGICAL assignment. In the
following, if a > 0.0 is true, .TRUE. is stored to Positive; otherwise, Positive
receives .FALSE.

LOGICAL FUNCTION Positive(a)


IMPLICIT NONE

REAL, INTENT(IN) :: a

Positive = a > 0.0


END FUNCTION Positive

• The following function, LargerRoot, takes three REAL formal arguments and returns
a REAL function value. It returns the larger root of a quadratic equation ax2 + bx + c
= 0.

REAL FUNCTION LargerRoot(a, b, c)


IMPLICIT NONE

REAL, INTENT(IN) :: a
REAL, INTENT(IN) :: b
REAL, INTENT(IN) :: c
REAL :: d, r1, r2

d = SQRT(b*b - 4.0*a*c)
r1= (-b + d) / (2.0*a)
r2= (-b - d) / (2.0*a)
IF(r1 >= r2) THEN
LargerRoot = r1
ELSE
LargerRoot = r2
END IF
END FUNCTION LargerRoot

The above example shows that you can declare other variables such as d, r1 and r2
if they are needed.

• The following function, Factorial(), has only one INTEGER formal argument n >= 0,
and computes and returns the factorial of n, n!.

INTEGER FUNCTION Factorial(n)


IMPLICIT NONE

INTEGER, INTENT(IN) :: n
INTEGER :: i, Ans

Ans = 1
DO i = 1, n
Ans = Ans * i
END DO
Factorial = Ans
END FUNCTION

Note that the function name Factorial is not used in any computation. Instead, a
new INTEGER variable is used for computing n!. The final value of Ans is stored to
Factorial before leaving the function.

If Factorial is involved in computation like the following:

INTEGER FUNCTION Factorial(n)


IMPLICIT NONE

INTEGER, INTENT(IN) :: n
INTEGER :: i

Factorial = 1
DO i = 1, n
Factorial = Factorial * i
END DO
END FUNCTION

then there is a mistake although the above program looks normal. The reason is that
the function name cannot appear in the right-hand side in any expression of that
function.

• The following function GetNumber() does not have any formal arguments and
returns an INTEGER function value. This function has a DO-loop which keeps asking
the user to input a positive number. The input is read into the function name. If this
value is positive, then EXIT and the function returns the value in GetNumber.
Otherwise, the loop goes back and asks the user again for a new input value.

REAL FUNCTION GetNumber()


IMPLICIT NONE

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

Forget the type of a FUNCTION.

FUNCTION DoSomething(a, b)
IMPLICIT NONE
INTEGER, INTENT(IN) :: a, b

DoSomthing = SQRT(a*a + b*b)


END FUNCTION DoSomthing

If there is no type, you will not be able to determine if the returned value is an
INTEGER, a REAL or something else.

Forget INTENT(IN).

REAL FUNCTION DoSomething(a, b)


IMPLICIT NONE

INTEGER :: a, b

DoSomthing = SQRT(a*a + b*b)


END FUNCTION DoSomthing

Actually, this is not an 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).

REAL FUNCTION DoSomething(a, b)


IMPLICIT NONE

INTEGER, INTENT(IN) :: a, b

IF (a > b) THEN
a = a - b
ELSE
a = a + b
END IF
DoSomthing = SQRT(a*a + b*b)
END FUNCTION DoSomthing

Since formal argument a is declared with INTENT(IN), its value cannot be changed.

• Forget to store a value to the function name.

REAL FUNCTION DoSomething(a, b)


IMPLICIT NONE

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.

REAL FUNCTION DoSomething(a, b)


IMPLICIT NONE

INTEGER, INTENT(IN) :: a, b

DoSomething = a*a + b*b


DoSomething = SQRT(DoSomething)
END FUNCTION DoSomthing

In the above, function name DoSomething appears in the right-hand side of the
second expression. This is a mistake. Only a special type of functions, RECURSIVE
functions, could have their names in the right-hand side of expressions.

• Only the most recent value stored in the function name will be returned..

REAL FUNCTION DoSomething(a, b)


IMPLICIT NONE

INTEGER, INTENT(IN) :: a, b

DoSomething = a*a + b*b


DoSomething = SQRT(a*a - b*b)
END FUNCTION DoSomthing

In the above, the value of SQRT(a*a-b*b) rather than the value of a*a + b*b is
returned. In fact, this is obvious. Since the name of a function can be considered as a
special variable name, the second assignment overwrites the previous value.

USING FUNCTIONS

The way of using a user-defined function is exactly identical to that of using Fortran intrinsic
functions. One can use a function in an expression and in a WRITE. Suppose we have the
following function:

REAL FUNCTION Average(x, y, z)


IMPLICIT NONE

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:

..... = ..... + Average(1.0, 2.0, 3.0) * .....


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.

Please keep the following important rules in mind:

The number of formal arguments and actual arguments must be equal.

..... = ... + Average(1.0, 2.0, 3.0, 4.0) * ....


..... = ... - Average(3.0, 6.0) + .....

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.

WRITE(*,*) Average(1, 2.5, 3.7)

In the above example, the first actual argument is an INTEGER which doe not match
with the type of the first formal argument. Thus, it is incorrect.

The actual arguments can be constants, variables and even expressions.

REAL :: a = 1.0, b = 2.0, c = 3.0

..... = ... + Average(1.0, 2.0, 3.0) + .....


..... = ... + Average(a, b, c) + .....
..... = ... + Average(a+b, b*c, (b+c)/a) + .....

In the above, the first line shows the use of constants as actual arguments. The
second line uses variables, while the third uses expression. In the third line, the result
of evaluating a+b, b*c and (b+c)/a will be supplied to the three formal arguments of
function Average().

Please continue with the next page on argument association

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.

INTEGER :: a, b, c INTEGER FUNCTION Small(x, y, z)


IMPLICIT NONE
a = 10 INTEGER, INTENT(IN) :: x, y, z
b = 5
c = 13 IF (x <= y .AND. x <= z) THEN
WRITE(*,*) Small(a,b,c) Small = x
WRITE(*,*) Small(a+b,b+c,c) ELSE IF (y <= x .AND. y <= z) THEN
WRITE(*,*) Small(1, 5, 3) Small = y
WRITE(*,*) Small((a),(b),(c)) ELSE
Small = z
END IF
END FUNCTION Small

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.

Thus, x, y and z receive 10, 5 and 13, respectively.

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.

WHERE DO MY FUNCTIONS GO?


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. N OTE ALSO THAT END
PROGRAM MUST BE THE LAST LINE OF YOUR PROGRAM.

PROGRAM Avg
IMPLICIT NONE
REAL :: a, b, c, Mean

READ(*,*) a, b, c
Mean = Average(a, b, c)
WRITE(*,*) a, b, c, Mean

CONTAINS
REAL FUNCTION Average(a, b, c)
IMPLICIT NONE
REAL, INTENT(IN) :: a, b, c
Average = (a + b + c) / 3.0
END FUNCTION Average
END PROGRAM Avg

THE FOLLOWING PROGRAM "CONTAINS " TWO FUNCTIONS LARGE() AND GEOMEAN(). THE ORDER OF
THESE FUNCTIONS ARE UNIMPORTANT .
PROGRAM TwoFunctions
IMPLICIT NONE
INTEGER :: a, b, BiggerOne
REAL :: GeometricMean

READ(*,*) a, b
BiggerOne = Large(a,b)
GeometricMean = GeoMean(a,b)
WRITE(*,*) 'Input = ', a, b
WRITE(*,*) 'Larger one = ', BiggerOne
WRITE(*,*) 'Geometric Mean = ', GeometricMean

CONTAINS
INTEGER FUNCTION Large(a, b)
IMPLICIT NONE
INTEGER, INTENT(IN) :: a, b
IF (a >= b) THEN
Large = a
ELSE
Large = b
END IF
END FUNCTION Large

REAL FUNCTION GeoMean(a, b)


IMPLICIT NONE
INTEGER, INTENT(IN) :: a, b
GeoMean = SQRT(REAL(a*b))
END FUNCTION GeoMean
END PROGRAM TwoFunctions
A IMPORTANT NOTE
Although in general a function can "contain"
other functions,
an internal function CANNOT contain any
other functions.

In the following example, the main program "contains" an internal function InternalFunction(),
which in turn contains another internal function Funct(). This is incorrect, since an internal
function cannot contain another internal function. In other words, the internal functions of a main
program must be on the same level.

PROGRAM Wrong
IMPLICIT NONE
.........
CONTAINS
INTEGER FUNCTION InternalFunction(.....)
IMPLICIT NONE
........
CONTAINS
REAL FUNCTION Funct(.....)
IMPLICIT NONE
........
END FUNCTION Funct
END FUNCTION InternalFunction
END PROGRAM Wrong
Please continue with the next important topic about scope rules.

SCOPE RULES

Since a main program could contain many functions and in fact a function can contain other
functions (i.e., nested functions), one may ask the following questions:

1. Could a function use a variable declared in the main program?


2. Could a main program use a variable declared in one of its function?

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.

The simplest rule is the following:

The scope of an entity is the


Scope
program or function
Rule 1
in which it is declared.

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

REAL FUNCTION Funct2(u, v)


IMPLICIT NONE
REAL, INTENT(IN) :: u, v
..........
END FUNCTION Funct2
END PROGRAM Scope_1
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().

This comes the second scope rule:

A global entity is visible to all contained


Scope functions,
Rule 2 including the function in which that
entity is declared.

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

INTEGER FUNCTION Mul(x, y)


IMPLICIT NONE
INTEGER, INTENT(IN) :: x, y
Mul = x * y
END FUNCTION Mul
END PROGRAM Scope_2

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

INTEGER FUNCTION Mul(x, y)


IMPLICIT NONE
INTEGER, INTENT(IN) :: x, y
Mul = x * y
END FUNCTION Mul
END PROGRAM Scope_2

WHAT IF THERE ARE NAME CONFLICTS ?


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:

An entity declared in the scope of another


Scope entity is always
Rule 3 a different entity even if their names are
identical.
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

INTEGER FUNCTION Sum(n)


IMPLICIT NONE
INTEGER, INTENT(IN) :: n
INTEGER :: i, s
s = 0
DO i = 1, n
s = s + i
END DO
Sum = s
END FUNCTION Sum
END PROGRAM Scope_3

Programming Examples:
COMPUTING CUBES

PROBLEM STATEMENT

Write a program to compute the cubes of 1, 2, 3, ..., 10 in both INTEGER and REAL types. It is
required to write a function intCube() for computing the cube of an integer and a function
realCube() for computing the cube of a real.

SOLUTION
! -----------------------------------------------------
! This program display the cubes of INTEGERs and
! REALs. The cubes are computed with two functions:
! intCube() and realCube().
! -----------------------------------------------------

PROGRAM Cubes
IMPLICIT NONE
INTEGER, PARAMETER :: Iterations = 10
INTEGER :: i
REAL :: x

DO i = 1, Iterations
x = i
WRITE(*,*) i, x, intCube(i), realCube(x)
END DO

CONTAINS

! -----------------------------------------------------
! INTEGER FUNCTION intCube() :
! This function returns the cube of the argument.
! -----------------------------------------------------

INTEGER FUNCTION intCube(Number)


IMPLICIT NONE

INTEGER, INTENT(IN) :: Number

intCube = Number*Number*Number
END FUNCTION intCube

! -----------------------------------------------------
! REAL FUNCTION realCube() :
! This function returns the cube of the argument.
! -----------------------------------------------------

REAL FUNCTION realCube(Number)


IMPLICIT NONE

REAL, INTENT(IN) :: Number

realCube = Number*Number*Number
END FUNCTION realCube

END PROGRAM Cubes


Click here to download this program.

PROGRAM INPUT AND OUTPUT


The following is the output from the above program.

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.

COMPUTING MEANS - REVISITED

PROBLEM STATEMENT

The arithmetic, geometric and harmonic means of three positive numbers are defined by the
following formulas:

Write a program to read three positive numbers and use three functions to compute the
arithmetic, geometric and harmonic means.

SOLUTION
! ----------------------------------------------------------
! This program contains three functions for computing the
! arithmetic, geometric and harmonic means of three REALs.
! ----------------------------------------------------------

PROGRAM ComputingMeans
IMPLICIT NONE

REAL :: a, b, c

READ(*,*) a, b, c
WRITE(*,*) 'Input: ', a, b, c
WRITE(*,*)
WRITE(*,*) 'Arithmetic mean = ', ArithMean(a, b, c)
WRITE(*,*) 'Geometric mean = ', GeoMean(a, b, c)
WRITE(*,*) 'Harmonic mean = ', HarmonMean(a, b, c)

CONTAINS

! ----------------------------------------------------------
! REAL FUNCTION ArithMean() :
! This function computes the arithmetic mean of its
! three REAL arguments.
! ----------------------------------------------------------
REAL FUNCTION ArithMean(a, b, c)
IMPLICIT NONE

REAL, INTENT(IN) :: a, b, c

ArithMean = (a + b + c) /3.0
END FUNCTION ArithMean

! ----------------------------------------------------------
! REAL FUNCTION GeoMean() :
! This function computes the geometric mean of its
! three REAL arguments.
! ----------------------------------------------------------

REAL FUNCTION GeoMean(a, b, c)


IMPLICIT NONE

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 FUNCTION HarmonMean(a, b, c)


IMPLICIT NONE

REAL, INTENT(IN) :: a, b, c

HarmonMean = 3.0 / (1.0/a + 1.0/b + 1.0/c)


END FUNCTION HarmonMean

END PROGRAM ComputingMeans


Click here to download this program.

PROGRAM INPUT AND OUTPUT


The following is the output from the above program.

Input: 10., 15., 18.

Arithmetic mean = 14.333333


Geometric mean = 13.9247675
Harmonic mean = 13.5

DISCUSSION

• Each of these functions is simple and does not require further explanation.
• Note that the main program and all three functions use the same names a, b and c.
By Scope Rule 3, they are all different entities. That is, when function ArithMean()
is using a, it is using its own local formal argument rather than the global variable a
declared in the main program.
CM AND INCH CONVERSION

PROBLEM STATEMENT

It is known that 1 cm is equal to 0.3937 inch and 1 inch is equal to 2.54 cm. Write a program to
convert 0, 0.5, 1, 1.5, ..., 8, 8.5, 9, 9.5, and 10 from cm to inch and from inch to cm.

SOLUTION
! ---------------------------------------------------------------
! This program "contains" two REAL functions:
! (1) Cm_to_Inch() takes a real inch unit and converts
! it to cm unit, and
! (2) Inch_to_cm() takes a real cm unit and converts it
! to inch unit.
! The main program uses these functions to convert 0, 0.5, 1, 1.5,
! 2.0, 2.5, ..., 8.0, 8.5, 9.0, 9.5 and 10.0 inch (resp., cm) to
! cm (resp., inch).
! ---------------------------------------------------------------

PROGRAM Conversion
IMPLICIT NONE

REAL, PARAMETER :: Initial = 0.0, Final = 10.0, Step = 0.5


REAL :: x

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 FUNCTION Cm_to_Inch(cm)


IMPLICIT NONE

REAL, INTENT(IN) :: cm
REAL, PARAMETER :: To_Inch = 0.3937 ! conversion factor

Cm_to_Inch = To_Inch * cm
END FUNCTION Cm_to_Inch

! ---------------------------------------------------------------
! REAL FUNCTION Inch_to_Cm()
! This function converts its real input in inch to cm.
! ---------------------------------------------------------------
REAL FUNCTION Inch_to_Cm(inch)
IMPLICIT NONE

REAL, INTENT(IN) :: inch


REAL, PARAMETER :: To_Cm = 2.54 ! conversion factor

Inch_to_Cm = To_Cm * inch


END FUNCTION Inch_to_Cm

END PROGRAM Conversion


Click here to download this program.

PROGRAM INPUT AND OUTPUT


The following is the output from the above program.

0.E+0cm = 0.E+0inch and 0.E+0inch = 0.E+0cm


0.5cm = 0.196850002inch and 0.5inch = 1.26999998cm
1.cm = 0.393700004inch and 1.inch = 2.53999996cm
1.5cm = 0.590550005inch and 1.5inch = 3.80999994cm
2.cm = 0.787400007inch and 2.inch = 5.07999992cm
2.5cm = 0.984250009inch and 2.5inch = 6.3499999cm
3.cm = 1.18110001inch and 3.inch = 7.61999989cm
3.5cm = 1.37794995inch and 3.5inch = 8.88999939cm
4.cm = 1.57480001inch and 4.inch = 10.1599998cm
4.5cm = 1.77165008inch and 4.5inch = 11.4300003cm
5.cm = 1.96850002inch and 5.inch = 12.6999998cm
5.5cm = 2.16534996inch and 5.5inch = 13.9699993cm
6.cm = 2.36220002inch and 6.inch = 15.2399998cm
6.5cm = 2.55905008inch and 6.5inch = 16.5100002cm
7.cm = 2.75589991inch and 7.inch = 17.7799988cm
7.5cm = 2.95274997inch and 7.5inch = 19.0499992cm
8.cm = 3.14960003inch and 8.inch = 20.3199997cm
8.5cm = 3.34645009inch and 8.5inch = 21.5900002cm
9.cm = 3.54330015inch and 9.inch = 22.8600006cm
9.5cm = 3.74014997inch and 9.5inch = 24.1299992cm
10.cm = 3.93700004inch and 10.inch = 25.3999996cm

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.

HERON'S FORMULA FOR COMPUTING TRIANGLE AREA - REVISITED


PROBLEM STATEMENT
Given a triangle with side lengths a, b and c, its area can be computed using the Heron's
formula:

where s is the half of the perimeter length:

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

LOGICAL FUNCTION TriangleTest(a, b, c)


IMPLICIT NONE

REAL, INTENT(IN) :: a, b, c
LOGICAL :: test1, test2

test1 = (a > 0.0) .AND. (b > 0.0) .AND. (c > 0.0)


test2 = (a + b > c) .AND. (a + c > b) .AND. (b + c > a)
TriangleTest = test1 .AND. test2 ! both must be .TRUE.
END FUNCTION TriangleTest

! --------------------------------------------------------------------
! 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 FUNCTION Area(a, b, c)


IMPLICIT NONE

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

END PROGRAM HeronFormula

Click here to download this program.

PROGRAM INPUT AND OUTPUT


The following is the output from the above program.

Three sides of a triangle please -->


-3.0 4.0 5.0
Input sides are -3., 4., 5.
Your input CANNOT form a triangle. Try again
Three sides of a triangle please -->
1.0 3.0 4.0
Input sides are 1., 3., 4.
Your input CANNOT form a triangle. Try again
Three sides of a triangle please -->
6.0 8.0 10.0
Input sides are 6., 8., 10.
Triangle area is 24.

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.

COMMUTING THE COMBINATORIAL COEFFICIENT

PROBLEM STATEMENT

The combinatorial coefficient C(n,r) is defined as follows:

where 0 <= r <= n must hold. Write a program that keeps reading in values for n and r, exits if
both values are zeros, uses a LOGICAL function to test if 0 <= r <= n holds, and computes
C(n,r) with an INTEGER function.

SOLUTION
! ---------------------------------------------------------------
! This program computes the combinatorial coefficient C(n,r):
!
! n!
! C(n,r) = -------------
! r! x (n-r)!
!
! It asks for two integers and uses Cnr(n,r) to compute the value.
! If 0 <= r <= n does not hold, Cnr() returns -1 so that the main
! program would know the input values are incorrect. Otherwise,
! Cnr() returns the desired combinatorial coefficient.
!
! Note that if the input values are zeros, this program stops.
! ---------------------------------------------------------------

PROGRAM Combinatorial
IMPLICIT NONE

INTEGER :: n, r, Answer

DO
WRITE(*,*)
WRITE(*,*) "Two integers n and r (0 <= r <= n) please "
WRITE(*,*) "0 0 to stop --> "
READ(*,*) n, r
IF (n == 0 .AND. r == 0) EXIT
WRITE(*,*) "Your input:"
WRITE(*,*) " n = ", n
WRITE(*,*) " r = ", r
Answer = Cnr(n, r)
IF (Answer < 0) THEN
WRITE(*,*) "Incorrect input"
ELSE
WRITE(*,*) " C(n,r) = ", Answer
END IF
END DO

CONTAINS

! ---------------------------------------------------------------
! INTEGER FUNCTION Cnr(n,r)
! This function receives n and r, uses LOGICAL function Test()
! to verify if the condition 0 <= r <= n holds, and uses
! Factorial() to compute n!, r! and (n-r)!.
! ---------------------------------------------------------------

INTEGER FUNCTION Cnr(n, r)


IMPLICIT NONE
INTEGER, INTENT(IN) :: n, r

IF (Test(n,r)) THEN
Cnr = Factorial(n)/(Factorial(r)*Factorial(n-r))
ELSE
Cnr = -1
END IF
END FUNCTION Cnr

! ---------------------------------------------------------------
! LOGICAL FUNCTION Test()
! This function receives n and r. If 0 <= r <= n holds, it
! returns .TRUE.; otherwise, it returns .FALSE.
! ---------------------------------------------------------------
LOGICAL FUNCTION Test(n, r)
IMPLICIT NONE
INTEGER, INTENT(IN) :: n, r

Test = (0 <= r) .AND. (r <= n)


END FUNCTION Test

! ---------------------------------------------------------------
! INTEGER FUNCTION Factorial()
! This function receives a non-negative integer and computes
! its factorial.
! ---------------------------------------------------------------

INTEGER FUNCTION Factorial(k)


IMPLICIT NONE
INTEGER, INTENT(IN) :: k
INTEGER :: Ans, i

Ans = 1
DO i = 1, k
Ans = Ans * i
END DO
Factorial = Ans
END FUNCTION Factorial

END PROGRAM Combinatorial


Click here to download this program.

PROGRAM INPUT AND OUTPUT


The following is the output from the above program.

Two integers n and r (0 <= r <= n) please


0 0 to stop -->
10 4
Your input:
n = 10
r = 4
C(n,r) = 210

Two integers n and r (0 <= r <= n) please


0 0 to stop -->
7 6
Your input:
n = 7
r = 6
C(n,r) = 7

Two integers n and r (0 <= r <= n) please


0 0 to stop -->
4 8
Your input:
n = 4
r = 8
Incorrect input
Two integers n and r (0 <= r <= n) please
0 0 to stop -->
-3 5
Your input:
n = -3
r = 5
Incorrect input

Two integers n and r (0 <= r <= n) please


0 0 to stop -->
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.

COMPUTING SQUARE ROOTS WITH NEWTON'S METHOD

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

REAL :: Begin, End, Step


REAL :: x, SQRTx, MySQRTx, Error

READ(*,*) Begin, End, Step ! read in init, final and step


x = Begin ! x starts with the init value
DO
IF (x > End) EXIT ! exit if x > the final value
SQRTx = SQRT(x) ! find square root with SQRT()
MySQRTx = MySqrt(x) ! do the same with my sqrt()
Error = ABS(SQRTx - MySQRTx) ! compute the absolute error
WRITE(*,*) x, SQRTx, MySQRTx, Error ! display the results
x = x + Step ! move on to the next value
END DO

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

REAL FUNCTION MySqrt(Input)


IMPLICIT NONE
REAL, INTENT(IN) :: Input
REAL :: X, NewX
REAL, PARAMETER :: Tolerance = 0.00001

IF (Input == 0.0) THEN ! if the input is zero


MySqrt = 0.0 ! returns zero
ELSE ! otherwise,
X = ABS(Input) ! use absolute value
DO ! for each iteration
NewX = 0.5*(X + Input/X) ! compute a new approximation
IF (ABS(X - NewX) < Tolerance) EXIT ! if very close, exit
X = NewX ! otherwise, keep the new one
END DO
MySqrt = NewX
END IF
END FUNCTION MySqrt

END PROGRAM SquareRoot


Click here to download this program.

PROGRAM INPUT AND OUTPUT


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.

0.E+0, 0.E+0, 0.E+0, 0.E+0


0.5, 0.707106769, 0.707106769, 0.E+0
1., 1., 1., 0.E+0
1.5, 1.22474492, 1.2247448, 1.192092896E-7
2., 1.41421354, 1.41421354, 0.E+0
2.5, 1.58113885, 1.58113885, 0.E+0
3., 1.73205078, 1.7320509, 1.192092896E-7
3.5, 1.87082875, 1.87082863, 1.192092896E-7
4., 2., 2., 0.E+0
4.5, 2.12132025, 2.12132025, 0.E+0
5., 2.23606801, 2.23606801, 0.E+0
5.5, 2.34520793, 2.34520793, 0.E+0
6., 2.44948983, 2.44948959, 2.384185791E-7
6.5, 2.54950976, 2.54950976, 0.E+0
7., 2.64575124, 2.64575148, 2.384185791E-7
7.5, 2.73861289, 2.73861265, 2.384185791E-7
8., 2.82842708, 2.82842708, 0.E+0
8.5, 2.91547585, 2.91547585, 0.E+0
9., 3., 3., 0.E+0
9.5, 3.08220696, 3.08220696, 0.E+0
10., 3.1622777, 3.1622777, 0.E+0

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.

DESIGNING A GREATEST COMMON DIVISOR FUNCTION

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

WRITE(*,*) 'Two positive integers please --> '


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

CONTAINS

! ---------------------------------------------------------
! INTEGER FUNCTION GCD():
! This function receives two INTEGER arguments and
! computes their GCD.
! ---------------------------------------------------------

INTEGER FUNCTION GCD(x, y)


IMPLICIT NONE

INTEGER, INTENT(IN) :: x, y ! we need x and y here


INTEGER :: a, b, c

a = x ! if x <= y, swap x and y


b = y ! since x and y are declared with
IF (a <= b) THEN ! INTENT(IN), they cannot be
c = a ! involved in this swapping process.
a = b ! So, a, b and c are used instead.
b = c
END IF

DO
c = MOD(a, b)
IF (c == 0) EXIT
a = b
b = c
END DO

GCD = b
END FUNCTION GCD

END PROGRAM GreatestCommonDivisor

Click here to download this program.


PROGRAM INPUT AND OUTPUT
The following is the output from the above program.

Two positive integers please -->


46332 71162
The GCD of is 26

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.

FINDING ALL PRIME NUMBERS IN THE RANGE OF 2 AND N - REVISITED

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

INTEGER :: Range, Number, Count

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

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

CONTAINS

! --------------------------------------------------------------------
! INTEGER FUNCTION GetNumber()
! This function does not require any formal argument. It keeps
! asking the reader for an integer until the input value is greater
! than or equal to 2.
! --------------------------------------------------------------------

INTEGER FUNCTION GetNumber()


IMPLICIT NONE

INTEGER :: Input

WRITE(*,*) 'What is the range ? '


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

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

LOGICAL FUNCTION Prime(Number)


IMPLICIT NONE

INTEGER, INTENT(IN) :: Number


INTEGER :: Divisor

IF (Number < 2) THEN


Prime = .FALSE.
ELSE IF (Number == 2) THEN
Prime = .TRUE.
ELSE IF (MOD(Number,2) == 0) THEN
Prime = .FALSE.
ELSE
Divisor = 3
DO
IF (Divisor*Divisor>Number .OR. MOD(Number,Divisor)==0) EXIT
Divisor = Divisor + 2
END DO
Prime = Divisor*Divisor > Number
END IF
END FUNCTION Prime

END PROGRAM Primes


Click here to download this program.

PROGRAM INPUT AND OUTPUT


The following is the output from the above program.

What is the range ?


-10
The range value must be >= 2. Your input = -10
Please try again:
0
The range value must be >= 2. Your input = 0
Please try again:
60

Prime number #1: 2


Prime number #2: 3
Prime number #3: 5
Prime number #4: 7
Prime number #5: 11
Prime number #6: 13
Prime number #7: 17
Prime number #8: 19
Prime number #9: 23
Prime number #10: 29
Prime number #11: 31
Prime number #12: 37
Prime number #13: 41
Prime number #14: 43
Prime number #15: 47
Prime number #16: 53
Prime number #17: 59

There are 17 primes in the range of 2 and 60

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.

THE BISECTION (BOZANO) EQUATION SOLVER

PROBLEM STATEMENT

Given a continuous equation f(x)=0 and two values a and b (a < b), if f(a)*f(b) < 0 (i.e., f(a) and
f(b) have opposite signs), it can be proved that there exists a root of f(x)=0 between a and b.
More precisely, there exists a c, a <= c <= b, such that f(c)=0 holds.

This result provides us with a method for solving equations. If we take the midpoint of a and b,
c=(a+b)/2, and computes its function value f(c), we have the following cases:

1. If f(c) is very small (i.e., smaller than a tolerance value), then c can be considered as
a root of f(x)=0 and we are done.
2. Otherwise, since f(a) and f(b) have opposite signs, the sign of f(c) is either identical
to that of f(a) or that of f(b).
o If the sign of f(c) is different from that of f(a), then since f(a) and f(c) have
opposite signs, f(x)=0 has a root in the range of a and c.
o If the sign of f(c) is different from that of f(b), then since f(b) and f(c) have
opposite signs, f(x)=0 has a root in the range of c and b.
3. Therefore, if the original interval [a,b] is replaced with [a,c] in the first case or
replaced with [c,b] in the second case, the length of the interval is reduced by half. If
continue this process, after a number of steps, the length of the interval could be
very small. However, since this small interval still contains a root of f(x)=0, we
actually find an approximation of that root!

Write a program that contains two functions: (1) Funct() - the function f(x) and (2) Solve()
- the equation solver based on the above theory. Then, reads in a and b and uses function
Solve() to find a root in the range of a and b. Note that before calling Solve, your program
should check if f(a)*f(b)<0 holds.

Your function Funct() is given below:

This function has a root near -0.89.

Since this process keeps dividing the intervals into two equal halves, it is usually referred to as
the bisection method. It is also known as Bozano's method.

SOLUTION
! --------------------------------------------------------------------
! This program solves equations with the Bisection Method. Given
! a function f(x) = 0. The bisection method starts with two values,
! a and b such that f(a) and f(b) have opposite signs. That is,
! f(a)*f(b) < 0. Then, it is guaranteed that f(x)=0 has a root in
! the range of a and b. This program reads in a and b (Left and Right
! in this program) and find the root in [a,b].
! In the following, function f() is REAL FUNCTION Funct() and
! solve() is the function for solving the equation.
! --------------------------------------------------------------------

PROGRAM Bisection
IMPLICIT NONE

REAL, PARAMETER :: Tolerance = 0.00001


REAL :: Left, fLeft
REAL :: Right, fRight
REAL :: Root

WRITE(*,*) 'This program can solves equation F(x) = 0'


WRITE(*,*) 'Please enter two values Left and Right such that '
WRITE(*,*) 'F(Left) and F(Right) have opposite signs.'
WRITE(*,*)
WRITE(*,*) 'Left and Right please --> '
READ(*,*) Left, Right ! read in Left and Right

fLeft = Funct(Left) ! compute their function values


fRight = Funct(Right)
WRITE(*,*)
WRITE(*,*) 'Left = ', Left, ' f(Left) = ', fLeft
WRITE(*,*) 'Right = ', Right, ' f(Right) = ', fRight
WRITE(*,*)
IF (fLeft*fRight > 0.0) THEN
WRITE(*,*) '*** ERROR: f(Left)*f(Right) must be negative ***'
ELSE
Root = Solve(Left, Right, Tolerance)
WRITE(*,*) 'A root is ', Root
END IF

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 Funct(x)


IMPLICIT NONE
REAL, INTENT(IN) :: x
REAL, PARAMETER :: PI = 3.1415926
REAL, PARAMETER :: a = 0.8475

Funct = SQRT(PI/2.0)*EXP(a*x) + x/(a*a + x*x)

END FUNCTION Funct

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

REAL FUNCTION Solve(Left, Right, Tolerance)


IMPLICIT NONE
REAL, INTENT(IN) :: Left, Right, Tolerance
REAL :: a, Fa, b, Fb, c, Fc
a = Left ! save Left and Right
b = Right

Fa = Funct(a) ! compute the function values


Fb = Funct(b)
IF (ABS(Fa) < Tolerance) THEN ! if f(a) is already small
Solve = a ! then a is a root
ELSE IF (ABS(Fb) < Tolerance) THEN ! is f(b) is small
Solve = b ! then b is a root
ELSE ! otherwise,
DO ! iterate ....
c = (a + b)/2.0 ! compute the middle point
Fc = Funct(c) ! and its function value
IF (ABS(Fc) < Tolerance) THEN ! is it very small?
Solve = c ! yes, c is a root
EXIT
ELSE IF (Fa*Fc < 0.0) THEN ! do f(a)*f(c) < 0 ?
b = c ! replace b with c
Fb = Fc ! and f(b) with f(c)
ELSE ! then f(c)*f(b) < 0 holds
a = c ! replace a with c
Fa = Fc ! and f(a) with f(c)
END IF
END DO ! go back and do it again
END IF
END FUNCTION Solve

END PROGRAM Bisection


Click here to download this program.

PROGRAM INPUT AND OUTPUT


The following is the output from the above program with correct input:

This program solves equation F(x) = 0


Please enter two values Left and Right such that
F(Left) and F(Right) have opposite signs.

Left and Right please -->


-10.0 0.0

Left = -10. f(Left) = -9.902540594E-2


Right = 0.E+0 f(Right) = 1.25331414

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.

This program solves equation F(x) = 0


Please enter two values Left and Right such that
F(Left) and F(Right) have opposite signs.

Left and Right please -->


-10.0 -1.0

Left = -10. f(Left) = -9.902540594E-2


Right = -1. f(Right) = -4.495930672E-2

*** ERROR: f(Left)*f(Right) must be negative ***

DISCUSSION

• Function Funct(x) returns the function value at x.


• The heart of this program is function Solve(). It takes three arguments Left, Right
and Tolerance and finds a root in the range of Left and Right.
• Since arguments Left and Right are declared with INTENT(IN), their values cannot
be changed. As a result, their values are copied to variables a and b.
• The function values of a and b are stored in Fa and Fb.
• If the absolute value of Fa (resp., Fb) is very small, one can consider a (resp., b) as a
root of the given equation.
• Otherwise, the midpoint c of a and b and its function value Fc are computed. If Fc is
very small, c is considered as a root.
• 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.

A Brief Introduction to Modules


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
The following is the syntax of a module:

MODULE module-name
IMPLICIT NONE
[specification part]
CONTAINS
[internal-functions]
END MODULE module-name

The differences between a program and a module are the following:


• The structure of a module is almost identical to the structure of a program.
• However, a module starts with the keyword MODULE and ends with END MODULE
rather than PROGRAM and END PROGRAM.
• A module has specification part and could contain internal function; but, it does not
have any statements between the specification part and the keyword CONTAINS.
• Consequently, a module does not contains statements to be executed as in a
program. A module can only contain declarations and functions to be used by other
modules and programs. This is perhaps one of the most important difference. As a
result, a module cannot exist alone; it must be used with other modules and
a main program

SHORT EXAMPLES
Here are some short examples of modules:

• The following is a very simple module. It has the specification part and does not have
any internal function. The specification part has two REAL PARAMETERs, namely PI
and g and one INTEGER variable Counter.

MODULE SomeConstants
IMPLICIT NONE
REAL, PARAMETER :: PI = 3.1415926
REAL, PARAMETER :: g = 980
INTEGER :: Counter
END MODULE SomeConstants

• The following module SumAverage does not have any specification part (hence no
IMPLICIT NONE); but it does contain two functions, Sum() and Average(). Please
note that function Average() uses Sum() to compute the sum of three REAL
numbers.

MODULE SumAverage

CONTAINS
REAL FUNCTION Sum(a, b, c)
IMPLICIT NONE
REAL, INTENT(IN) :: a, b, c
Sum = a + b + c
END FUNCTION Sum

REAL FUNCTION Average(a, b, c)


IMPLICIT NONE
REAL, INTENT(IN) :: a, b, c
Average = Sum(a,b,c)/2.0
END FUNCTION Average

END MODULE SumAverage

• 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

REAL FUNCTION DegreeToRadian(Degree)


IMPLICIT NONE
REAL, INTENT(IN) :: Degree
DegreeToRadian = Degree*PI/Degree180
END FUNCTION DegreeToRadian

REAL FUNCTION RadianToDegree(radian)


IMPLICIT NONE
REAL, INTENT(IN) :: Radian
RadianToDegree = Radian*Degree180/PI
END FUNCTION RadianToDegree

END MODULE DegreeRadianConversion

HOW TO USE A MODULE?

Once a module is written, its global entities (i.e., global PARAMETERs, global variables and
internal functions) can be made available to other modules and programs. The program or
module that wants to use a particular module must have a USE statement at its very beginning.
The USE statement has one of the following forms:

SYNTAX
The following form is the syntax of a module:

USE module-name

USE module-name, ONLY: name-1, name-2, ..., name-n

Here is the meaning of these USEs:

The first indicates that the current program or module wants to use the module whose
name is module-name. For example, the following main program indicates that it wants
to use the content of module SomeConstants:

PROGRAM MainProgram
USE SomeConstants
IMPLICIT NONE
..........
END PROGRAM MainProgram

Once a USE is specified in a program or in a module, every global entities of that used
module (i.e., PARAMETERs, variables, and internal functions) becomes available to this
program or this module. For example, if module SomeConstants is:

MODULE SomeConstants
IMPLICIT NONE
REAL, PARAMETER :: PI = 3.1415926
REAL, PARAMETER :: g = 980
INTEGER :: Counter
END MODULE SomeConstants

Then, program MainProgram can access to PARAMETERs PI and g and variable


Counter.

However, under many circumstances, a program or a module does not want to use
everything of the used module. For example, if program MainProgram only wants to
use PARAMETER PI and variable Counter and does not want to use g, then the second
form becomes very useful. In this case, one should add the keyword ONLY followed by a
colon :, followed by a list of names that the current program or module wants to use.

PROGRAM MainProgram
USE SomeConstants, ONLY: PI, Counter
IMPLICIT NONE
..........
END PROGRAM MainProgram

Thus, MainProgram can use PI and Counter of module SomeConstants; but,


MainProgram cannot 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:
• new-name => name-in-module

For example, if one wants to give a new name to Counter of module


SomeConstants, one should write:

NewCounter => Counter

Thus, in a program, whenever it uses MyCounter, this program is actually using


Counter of module SomeConstants.

This kind of renaming can be used with ONLY: or without ONLY:.

PROGRAM MainProgram
USE SomeConstants, ONLY: PI, MyCounter => Counter
IMPLICIT NONE
..........
END PROGRAM MainProgram

The above example wants to use PI of module SomeConstants. In this case, when
program MainProgram uses PI, it actually uses the PI of module SomeConstants.
Program MainProgram also uses Counter of module SomeConstants; but, in this
case, since there is a renaming, when MainProgram uses MyCounter it actually
uses Counter of module SomeConstants.

Renaming does not require ONLY:. In the following, MainProgram can use all contents
of module SomeConstants. When MainProgram uses PI and g, it uses the PI and g of
module SomeConstants; however, when MainProgram uses MyCounter, it actually
uses Counter of module SomeConstants.

PROGRAM MainProgram
USE SomeConstants, MyCounter => Counter
IMPLICIT NONE
..........
END PROGRAM MainProgram

Why do we need renaming? It is simple. In your program, you may have a variable
whose name is identical to an entity of a module that is being USEed. In this case,
renaming the variable name would clear the ambiguity.

PROGRAM MainProgram
USE SomeConstants, GravityConstant => g
IMPLICIT NONE
INTEGER :: e, f, g
..........
END PROGRAM MainProgram

In the above example, since MainProgram has a variable called g, which is the
same as PARAMETER g in module SomeConstants. By renaming g of
SomeConstants, MainProgram can use variable g for the variable and
GravityConstant for the PARAMETER g in module SomeConstants.

However, renaming is not a recommended feature. You should avoid using it


whenever possible.

COMPILE PROGRAMS WITH MODULES

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

f90 compute.f90 convert.f90 constants.f90 main.f90


If you do not want the executable to be called a.out, you can do the following:

f90 compute.f90 convert.f90 constants.f90 main.f90 -o main


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:

f90 A.f90 B.f90 C.f90 D.f90 E.f90 main.f90


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

f90 compute.o convert.o constants.o main.o


This would generate a.out. Or, you may want to use

f90 compute.o convert.o constants.o main.o -o main


so that your executable could be called main.

If you want compile your main program main.f90 with all .o files, then you need

f90 compute.o convert.o constants.o main.c


or

f90 compute.o convert.o constants.o main.c -o main


Note that the order of listing these .o files may be important. Please consult the rules
discussed earlier.

FACTORIAL AND COMBINATORIAL COEFFICIENT

PROBLEM STATEMENT

The combinatorial coefficient C(n,r) is defined as follows:

where 0 <= r <= n must hold. Write a module that contains two functions: (1) Factorial() and
(2) Combinatorial(). The former computes the factorial of its argument, while the latter uses the
former to compute the combinatorial coefficient. Then, write a main program that uses this
module.

SOLUTION
The following is the desired module:

! --------------------------------------------------------------------
! MODULE FactorialModule
! This module contains two procedures: Factorial(n) and
! Combinatorial(n,r). The first computes the factorial of an integer
! n and the second computes the combinatorial coefficient of two
! integers n and r.
! --------------------------------------------------------------------

MODULE FactorialModule
IMPLICIT NONE

CONTAINS

! --------------------------------------------------------------------
! FUNCTION Factorial() :
! This function accepts a non-negative integers and returns its
! Factorial.
! --------------------------------------------------------------------

INTEGER FUNCTION Factorial(n)


IMPLICIT NONE

INTEGER, INTENT(IN) :: n ! the argument


INTEGER :: Fact, i ! result

Fact = 1 ! initially, n!=1


DO i = 1, n ! this loop multiplies
Fact = Fact * i ! i to n!
END DO
Factorial = Fact

END FUNCTION Factorial

! --------------------------------------------------------------------
! FUNCTION Combinarotial():
! This function computes the combinatorial coefficient C(n,r).
! If 0 <= r <= n, this function returns C(n,r), which is computed as
! C(n,r) = n!/(r!*(n-r)!). Otherwise, it returns 0, indicating an
! error has occurred.
! --------------------------------------------------------------------

INTEGER FUNCTION Combinatorial(n, r)


IMPLICIT NONE

INTEGER, INTENT(IN) :: n, r
INTEGER :: Cnr

IF (0 <= r .AND. r <= n) THEN ! valid arguments ?


Cnr = Factorial(n) / (Factorial(r)*Factorial(n-r))
ELSE ! no,
Cnr = 0 ! zero is returned
END IF
Combinatorial = Cnr

END FUNCTION Combinatorial

END MODULE FactorialModule


Click here to download this program.

Here is the main program:

! --------------------------------------------------------------------
! 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

WRITE(*,*) 'Two non-negative integers --> '


READ(*,*) N, R

WRITE(*,*) N, '! = ', Factorial(N)


WRITE(*,*) R, '! = ', Factorial(R)

IF (R <= N) THEN ! if r <= n, do C(n,r)


WRITE(*,*) 'C(', N, ',', R, ') = ', Combinatorial(N, R)
ELSE ! otherwise, do C(r,n)
WRITE(*,*) 'C(', R, ',', N, ') = ', Combinatorial(R, N)
END IF

END PROGRAM ComputeFactorial


Click here to download this program.

PROGRAM INPUT AND OUTPUT


The following is the output from the above program.

Two non-negative integers -->


13 4
13! = 1932053504
4! = 24
C(13,4) = 221

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:
• f90 fact-m.f90 fact-1p.90

or with the following that generates an executable called fact1p:

f90 fact-m.f90 fact-1p.90 -o fact-1p

TRIGONOMETRIC FUNCTIONS USING DEGREE

PROBLEM STATEMENT
Trigonometric functions (i.e., sin(x) and cos(x)) use radian for their argument. Using modules,
you can design your own trigonometric functions that use degree. Write a module that contains
functions for converting radian to degree and degree to radian and sin(x) and cos(x) with
arguments in degree rather than in radian.

SOLUTION
The following is the desired module:

! --------------------------------------------------------------------
! MODULE MyTrigonometricFunctions:
! This module provides the following functions and constants
! (1) RadianToDegree() - converts its argument in radian to
! degree
! (2) DegreeToRadian() - converts its argument in degree to
! radian
! (3) MySIN() - compute the sine of its argument in
! degree
! (4) MyCOS() - compute the cosine of its argument
! in degree
! --------------------------------------------------------------------

MODULE MyTrigonometricFunctions
IMPLICIT NONE

REAL, PARAMETER :: PI = 3.1415926 ! some constants


REAL, PARAMETER :: Degree180 = 180.0
REAL, PARAMETER :: R_to_D = Degree180/PI
REAL, PARAMETER :: D_to_R = PI/Degree180

CONTAINS

! --------------------------------------------------------------------
! FUNCTION RadianToDegree():
! This function takes a REAL argument in radian and converts it to
! the equivalent degree.
! --------------------------------------------------------------------

REAL FUNCTION RadianToDegree(Radian)


IMPLICIT NONE
REAL, INTENT(IN) :: Radian

RadianToDegree = Radian * R_to_D


END FUNCTION RadianToDegree

! --------------------------------------------------------------------
! FUNCTION DegreeToRadian():
! This function takes a REAL argument in degree and converts it to
! the equivalent radian.
! --------------------------------------------------------------------

REAL FUNCTION DegreeToRadian(Degree)


IMPLICIT NONE
REAL, INTENT(IN) :: Degree

DegreeToRadian = Degree * D_to_R


END FUNCTION DegreeToRadian

! --------------------------------------------------------------------
! 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().
! --------------------------------------------------------------------

REAL FUNCTION MySIN(x)


IMPLICIT NONE
REAL, INTENT(IN) :: x

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().
! --------------------------------------------------------------------

REAL FUNCTION MyCOS(x)


IMPLICIT NONE
REAL, INTENT(IN) :: x

MyCOS = COS(DegreeToRadian(x))
END FUNCTION MyCOS

END MODULE MyTrigonometricFunctions


Click here to download this program.

Here is the main program:

! -----------------------------------------------------------------------
! 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

REAL :: Begin = -180.0 ! initial value


REAL :: Final = 180.0 ! final value
REAL :: Step = 10.0 ! step size
REAL :: x

WRITE(*,*) 'Value of PI = ', PI


WRITE(*,*)
x = Begin ! start with 180 degree
DO
IF (x > Final) EXIT ! if x > 180 degree, EXIT
WRITE(*,*) 'x = ', x, 'deg sin(x) = ', MySIN(x), &
' cos(x) = ', MyCOS(x)
x = x + Step ! advance x
END DO

END PROGRAM TrigonFunctTest


Click here to download this program.

PROGRAM INPUT AND OUTPUT


The following is the output from the above program.

Value of PI = 3.1415925

x = -180.deg sin(x) = 8.742277657E-8 cos(x) = -1.


x = -170.deg sin(x) = -0.173648298 cos(x) = -0.98480773
x = -160.deg sin(x) = -0.342020214 cos(x) = -0.939692616
x = -150.deg sin(x) = -0.50000006 cos(x) = -0.866025388
x = -140.deg sin(x) = -0.642787635 cos(x) = -0.766044438
x = -130.deg sin(x) = -0.766044438 cos(x) = -0.642787635
x = -120.deg sin(x) = -0.866025388 cos(x) = -0.50000006
x = -110.deg sin(x) = -0.939692616 cos(x) = -0.342020124
x = -100.deg sin(x) = -0.98480773 cos(x) = -0.173648193
x = -90.deg sin(x) = -1. cos(x) = -4.371138829E-8
x = -80.deg sin(x) = -0.98480773 cos(x) = 0.173648223
x = -70.deg sin(x) = -0.939692616 cos(x) = 0.342020154
x = -60.deg sin(x) = -0.866025448 cos(x) = 0.49999997
x = -50.deg sin(x) = -0.766044438 cos(x) = 0.642787635
x = -40.deg sin(x) = -0.642787576 cos(x) = 0.766044438
x = -30.deg sin(x) = -0.5 cos(x) = 0.866025388
x = -20.deg sin(x) = -0.342020124 cos(x) = 0.939692616
x = -10.deg sin(x) = -0.173648179 cos(x) = 0.98480773
x = 0.E+0deg sin(x) = 0.E+0 cos(x) = 1.
x = 10.deg sin(x) = 0.173648179 cos(x) = 0.98480773
x = 20.deg sin(x) = 0.342020124 cos(x) = 0.939692616
x = 30.deg sin(x) = 0.5 cos(x) = 0.866025388
x = 40.deg sin(x) = 0.642787576 cos(x) = 0.766044438
x = 50.deg sin(x) = 0.766044438 cos(x) = 0.642787635
x = 60.deg sin(x) = 0.866025448 cos(x) = 0.49999997
x = 70.deg sin(x) = 0.939692616 cos(x) = 0.342020154
x = 80.deg sin(x) = 0.98480773 cos(x) = 0.173648223
x = 90.deg sin(x) = 1. cos(x) = -4.371138829E-8
x = 100.deg sin(x) = 0.98480773 cos(x) = -0.173648193
x = 110.deg sin(x) = 0.939692616 cos(x) = -0.342020124
x = 120.deg sin(x) = 0.866025388 cos(x) = -0.50000006
x = 130.deg sin(x) = 0.766044438 cos(x) = -0.642787635
x = 140.deg sin(x) = 0.642787635 cos(x) = -0.766044438
x = 150.deg sin(x) = 0.50000006 cos(x) = -0.866025388
x = 160.deg sin(x) = 0.342020214 cos(x) = -0.939692616
x = 170.deg sin(x) = 0.173648298 cos(x) = -0.98480773
x = 180.deg sin(x) = -8.742277657E-8 cos(x) = -1.
DISCUSSION

• Module MyTrigonometricFunctions defines four constants:


1. PI,
2. Degree180,
3. R_to_D for radian to degree conversion, and
4. D_to_R for degree to radian conversion.
• Module MyTrigonometricFunctions contains four functions:
1. RadianToDegree() converts its radian argument to degree;
2. DegreeToRadian() converts its degree argument to radian;
3. MySIN() takes a degree argument and returns its sine value; and
4. MyCOS() takes a degree argument and returns its cosine value.
• In the module, MySIN(x) first converts its degree argument x to radian using
function DegreeToRadian() and supplies the result to the Fortran SIN() function for
computing the value of sine.
• The module uses MySIN() and MyCOS() rather than the same Fortran names SIN()
and COS() to avoid confusion.
• As described in the use of modules, the main program can use variables,
PARAMETERs and functions declared and defined in a module. Thus, the main
program can use the value of PARAMETER PI defined in module
MyTrigonometricFunctions. This is why there is no declaration of PI in the main
program.
• In the main program, REAL variable x starts with 180 (in degree) and steps through
180 (in degree) with a step size 10. For each value of x, its SIN() and COS() is
computed.
• If the main program and module MyTrigonometricFunctions are stored in files
trigon.f90 and tri-test.f90, respectively, then you can compile them together with
the following command:
• f90 trigon.f90 tri-test.90

or with the following that generates an executable called tri-test:

f90 trigon.f90 tri-test.90 -o tri-test

A LITTLE PRIVACY - PUBLIC/PRIVATE

All global entities of a module, by default, can be accessed by a program or another module
using the USE statement. But, it is possible to set some restrictions that some entities are private.
A private entity of a module can only be accessed within that module. On the other hand, one
can explicitly list those entities that can be accessed from outside. This is done with the PUBLIC
and PRIVATE statements:

SYNTAX
The following is the syntax of a module:

PUBLIC :: name-1, name-2, ..., name-n

PRIVATE :: name-1, name-2, ..., name-n


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.

You can have many PRIVATE and PUBLIC statements.

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

INTEGER :: SkyWalker, Princess


REAL :: BlackKnight
LOGICAL :: DeathStar

REAL, PARAMETER :: SecretConstant = 0.123456

PUBLIC :: SkyWalker, Princess


PRIVATE :: VolumeOfDeathStar
PRIVATE :: SecretConstant, BlackKnight

CONTAINS
INTEGER FUNCTION VolumeOfDeathStar()
..........
END FUNCTION WolumeOfDeathStar

REAL FUNCTION WeaponPower(SomeWeapon)


..........
END FUNCTION

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

REAL, PARAMETER :: PI = 3.1415926 ! some constants


REAL, PARAMETER :: Degree180 = 180.0
REAL, PARAMETER :: R_to_D = Degree180/PI
REAL, PARAMETER :: D_to_R = PI/Degree180

PRIVATE :: Degree180, R_to_D, D_to_R


PRIVATE :: RadianToDegree, DegreeToRadian
PUBLIC :: MySIN, MyCOS

CONTAINS

! --------------------------------------------------------------------
! FUNCTION RadianToDegree():
! This function takes a REAL argument in radian and converts it to
! the equivalent degree.
! --------------------------------------------------------------------

REAL FUNCTION RadianToDegree(Radian)


IMPLICIT NONE
REAL, INTENT(IN) :: Radian

RadianToDegree = Radian * R_to_D


END FUNCTION RadianToDegree

! --------------------------------------------------------------------
! FUNCTION DegreeToRadian():
! This function takes a REAL argument in degree and converts it to
! the equivalent radian.
! --------------------------------------------------------------------

REAL FUNCTION DegreeToRadian(Degree)


IMPLICIT NONE
REAL, INTENT(IN) :: Degree

DegreeToRadian = Degree * D_to_R


END FUNCTION DegreeToRadian

! --------------------------------------------------------------------
! 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().
! --------------------------------------------------------------------

REAL FUNCTION MySIN(x)


IMPLICIT NONE
REAL, INTENT(IN) :: x

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().
! --------------------------------------------------------------------

REAL FUNCTION MyCOS(x)


IMPLICIT NONE
REAL, INTENT(IN) :: x

MyCOS = COS(DegreeToRadian(x))
END FUNCTION MyCOS

END MODULE MyTrigonometricFunctions


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