Calculus Computer Lab Math 190: Fortran Lesson 1
Calculus Computer Lab Math 190: Fortran Lesson 1
Calculus Computer Lab Math 190: Fortran Lesson 1
Lab
Math 190
News
FORTRAN LESSON 1
Lab Schedule
Declarations End
Types Operations
#1 #1
Introduction
Fortran is one of the oldest programming languages devised, but it is also still one
of the most popular, especially among engineers and applied scientists. It was
developed in the 1950's at IBM. Part of the reason for Fortran's durability is that it
is particularly well-suited for mathematical programming; moreover, there are
millions of useful programs written in Fortran, created at considerable time and
expense, and understandably people are reluctant to trash these old programs and
switch to a new programming language.
The name Fortran originally referred to "Formula Translation", but it has long
since taken on its own meaning. There are several versions of Fortran around,
among them Fortran 77, Fortran 90, and Fortran 95. (The number denotes the year
of introduction.) Fortran 77 is probably still the most used, and it is the version
installed on UHUNIX and in the UH math lab. Even though this semester we have
thus far studied Basic, at the same time we have studied Fortran, because
commands and procedures are very similar in the two languages. Moving from
QuickBasic to Fortran is more a matter of change of terminology than anything
else.
Editing Fortran
A most peculiar feature of Fortran 77 is its line structure, which is a carryover from
the old days when programs were typed on punch cards. A punch card had 80
columns, and so does a line of Fortran code. A "c" in column 1 indicates a
comment (similar to REM in Basic). Columns 2-5 (usually left blank) are reserved
for line numbers. Column 6 is used only to indicate a continuation of a line too
long to fit on the card. Columns 7-72 contain the instructions of the program.
Columns 73-80 were originally used for numbering the punch cards, but are rarely
used nowadays - leave them blank and the compiler will ignore them.
Fortran is case insensitive - that is, it does not distinguish between capital and
small letters. Thus x and X refer to the same variable. Many programmers for
simplicity use all small letters, but you may do as you like. Also, after column six
Fortran does not recognize spaces (except for spaces inside quotations as in print
statements). In general, spaces are mostly for the purpose of making code more
readable by humans. When you type a Fortran program with an editor, make
certain the editor indents more than six spaces; then if you begin every line with an
indent you do not have to worry about counting six spaces at the beginnings of
lines.
Let us go through the steps of editing, compiling, and running a short program.
First open Notepad under Windows, or type "edit" (and return) under a DOS
prompt to open the DOS editor. (When you double-click the Fortran icon on a
math lab computer, you get a DOS prompt.) Beginning each line with an indent
(except for the fourth line, where the "c" must be placed in the first column), type
the program exhibited below; the program computes the area of a circle of radius r,
as input by the user. The resulting file that you save is called the source file for the
program.
program circlearea
real r, area, pi
parameter (pi = 3.14159)
c This program computes the area of a circle.
print *, "What is the radius?"
read *, r
area = pi * r ** 2
print *, "The area is", area
print *, "Bye!"
end
The first statement above gives the program name, the second declares that "r",
"area", and "pi" will be single precision real quantities, and the third announces
that pi has the value 3.14159. The fourth statement, beginning with "c" in column
1, is a comment describing what the program does; such comments are for the
benefit of the programmer and are ignored by Fortran. The fifth statement prompts
the user for the radius of the circle, and the sixth accepts this input. The seventh
statement computes the area and the eighth informs the user of this area. Finally,
the last two statements bid goodbye and terminate the program.
The name for a source file in Fortran must end with the extension ".f" before the
compiler recognizes it. After you have typed the above program, save the file as
area.f. (If you type the file in Notepad, include the whole name in quotes when you
save it, as otherwise the extension .txt will be added to the name.) The file will be
saved to your h directory in the math lab. Under a DOS prompt you can view the
files in this directory by typingdir and enter; under Windows you can double-click
"My Computer" and then the icon for the h drive.
Compiling
After you have created and saved a source file, you next must compile this file.
Open a Fortran window and enter g77 name.f, where in place of name you insert
the name of your source file. (If the source file resides in a directory different from
that of the Fortran program, you will have to include also the directory path of the
file.) To compile the file of our example above, in the math computer lab you just
enter g77 area.f.
If your program has mistakes (which usually happens on the first attempt at
compiling), instead of a compiled file you will get Fortran error messages pointing
out problems. Some of these messages can be hard to decipher, but after reading
hundreds of them you will get better at it. If your program has no mistakes Fortran
will simply return a DOS prompt - that is good news because it means Fortran has
successfully created a compiled file. By default this new file is given the
name a.exe. (You can give the compiled file a name of your own choosing by
typing g77 area.f -o name.exe to compile the program - but usually there is no
reason not to accept the default name.) Your compiled file, also located in the h
directory, is now executable - that means the program is ready to run.
Running a Program
If your compiled file has the default name a.exe, you simply type a and return to
run it (or name and return if you gave the file another name). After you run the
program and see how it works, you can return to your editor and revise it as you
wish. It is perhaps better to keep two windows open - both the Fortran window and
the editing window - so that you can quickly switch from one to the other with a
mouse-click. After revising a program, you must save and compile it again before
changes take effect.
If you do enough Fortran programming, sooner or later you will err and create and
run a program that never stops. In such a situation, type "Control-C" to interrupt
the execution of the program.
Now that we have discussed the basic nuts and bolts of creating and running a
Fortran program, we discuss some terminology and commands. You will probably
find that most of these remind you of similar things in Basic.
Program
Every Fortran program must begin with a program line, giving the name of the
program. Here are examples:
program quadratic
program mortgage
program primes .
After the program name come the declaration statements, stating the types of the
variables used in the program. A variable name consists of characters chosen from
the letters a-z and the digits 0-9; the first character of the name must be a letter.
You are not allowed to use your program name as a variable, nor are you allowed
to use words reserved for the Fortran language, such as "program", "real", "end",
etc.
declare that r and area are single precision real variables, that M and N are integers,
and that a and b are double precision real variables.
If you do not declare the type of a variable, Fortran will by default make it an
integer if it starts with one of the letters i through n, and will make it a single
precision real variable otherwise. However, it is normal (and good) programming
practice to declare the type of every variable, as otherwise mistakes are easily
made.
The implicit quantifier before a type declaration makes all variables starting with
the listed letters of the specified type. For example, the declarations
make variables starting with i, j, k, l, m integers, and those starting with r, s, t real.
However, the implicit quantifier is probably best avoided, as programmers with
short memories will make mistakes.
Assignment
The equals sign "=" assigns the variable on the left side the value of the number or
expression on the right side (exactly as in Basic).
Parameter
The parameter statement works like CONST in Basic - it specifies a value for a
constant. The syntax is
parameter (name = constant expression)
where name is replaced by the name of the constant, and constant expression by an
expression involving only constants. Thus
specifies a value for the constant pi, while the succeeding statement
fixes values of new constants a and b in terms of the old constant pi. Remember
that once a constant is defined you are not allowed to change its value later.
All parameter statements must appear before the first executable statement.
Comments
Print *
The command "print *" is analogous to PRINT in Basic; it instructs Fortran to print
items to the screen. Examples are
print *, x
print *, "The solution is ", x
print *, 'The radius is', r, 'and the area is', area
Note that a comma follows "print *", and that commas (instead of semicolons as in
Basic) appear between successive items to be printed. Observe also that either
double or single quotes may enclose strings. The command "print *" on a line by
itself (without a comma) serves as a line feed.
Read *
In the first example the program pauses to allow the user to enter the radius. In the
second example the user types the values of A, B, and C, separated by returns;
alternatively, the user can type A, B, and C separated only by commas, and then
one final return.
End
The end statement marks the end of the main Fortran program or of a subprogram.
(It cannot be used in the middle of the program, as in Basic.)
Operations of Arithmetic
Subtraction x-y
Multiplication x*y
Division x/y
Exponentiation x ** y
Be careful with division. If m and n are integers, then m/n is truncated to its integer
part. Thus 3/4 is evaluated as 0, and 25/6 as 4. When working with constants rather
than variables you can avoid this problem by using periods after integers. For
example 3./4. is evaluated in the standard way as .75, as Fortran treats 3. and 4. as
real variables rather than as integers.
Intrinsic Functions
Many standard mathematical functions are built into Fortran - these are
called intrinsic functions. Below is a table of some of the functions most
commonly used in mathematical programming. All trig functions work in radians.
(Note that arguments of functions must be enclosed in parentheses.)
Function Description
acos(x) arccosine of x
asin(x) arcsine of x
atan(x) arctangent of x
cos(x) cosine of x
sin(x) sine of x
tan(x) tangent of x
FORTRAN LESSON 2
Lesson Topics
Logical Expressions Go To
Stop Do Loops
Labels
# 1 # 2 # 3 # 4 # 5 # 6 # 7 # 8 # 9 # 10 # 1 # 2 # 3 # 4 # 5 # 6 # 7 # 8 # 9 # 10
Logical Expressions
.eq. equals
.and. and
.or. or
.not. not
"If … Then … Else" constructions in Fortran are pretty much like those in Basic,
with but a few minor modifications. First, instead of using in the tests symbols like
"=", "<", ">=", etc., as in Basic, you must use the abbreviations in the preceding
table. Also, tests must be enclosed in parentheses, and "else if" may be two words.
Here are several examples:
1) if (x .gt. 0) print *, "x is positive"
3) if (x .ge. 0) then
y = sqrt(x)
print *, y, " squared = ", x
end if
4) if (x .ge. 0) then
y = sqrt(x)
print *, y, " squared = ", x
else
print *, "x has no square root"
end if
5) if (x .gt. 0) then
print *, "x is positive"
y = sqrt(x)
else if (x .lt. 0) then
print *, "x is negative"
go to 60
else if (x .eq. 0) then
print *, "x is zero"
y=0
end if
Observe that, as in examples 1) and 2), the one-line "if" statement does not use
"then". Moreover, "else" appears on a line by itself, while "else if" shares the line
with the test condition and "then".
Stop
A stop statement stops the execution of a program. For instance, the sequence of
statements below terminates the program whenever n is less than zero:
if (n .lt. 0) then
print *, "Error - your age cannot be negative!"
stop
end if .
Do not confuse stop and end. Use end only as the very last statement in the
program, and use stop only to terminate the program before this last statement.
Violating these rules will fatally confuse the compiler - it regards an end statement
as the program's physical end.
Labels and Go To
Labels and the "go to" statement work as in Basic, except that a label must be a
number, and it must be typed in columns 2-5. Here is an example of a go
to command directing the action to a labeled statement:
if (x .lt. 0) go to 10
print *, "The square root of x is ", sqrt(x)
stop
10 print *, "x is negative and has no square root"
Character Variables
A character variable is analogous to a string variable in Basic. A character
variable must be declared at the beginning of the program, and attached to it in the
declaration must be a number following an asterisk "*"; this number indicates the
maximum number of symbols in the string. For example, the declaration statement
character name*20, ans*1
Do Loops
"For … Next" loops in Basic become "Do Loops" in Fortran. Such a loop begins
with a do statement, and ends with either end do, or a labeled continue statement.
Here are two loops that add the squares of the integers from 1 to 10:
sum = 0 | sum = 0
do i = 1, 10 | do 5 i = 1, 10
sum = sum + i ** 2 | sum = sum + i ** 2
end do | 5 continue
print *, "The sum is", sum | print *, "The sum is", sum
The end do and continue statements serve only to identify the end of the loop. The
limits of the loop may be variables as well as numbers (e.g.: do i = m, n). As in
Basic you may indicate a step size, which can be positive or negative. For example,
the statement
do i = 1, 9, 2
specifies that the loop variable i run over the odd numbers 1, 3, 5, 7, 9.
Loops can be nested, and nested loops can end on the same continue statement
(but not on the same end do statement). Here are two instances of nested loops
assigning the entries of a 10 x 10 matrix:
do i = 1, 10 | do 5 i = 1, 10
do j = 1, 10 | do 5 j = 1, 10
a(i,j) = i + j | a(i,j) = i + j
end do | 5 continue
end do |
FORTRAN LESSON 3
Lesson Topics
Integers Exponentials
#1#2#3#4#5#6#7#8#9 #1#2#3#4#5#6#7#8#9
Integers
For positive integers the plus sign is optional, but negative integers must be
preceded by a minus sign. Examples of numbers not considered integers by Fortran
are
Because of the decimal points, Fortran will regard 3. and 4.0 as real numbers.
An integer N in GNU Fortran must lie within the range
- 2,147,483,648 ≤ N ≤ 2,147,483,647 .
If you want Fortran to give you the correct value of 11/8, you tell it to compute
11./8., so that it interprets the numbers as real numbers and produces the correct
value 1.375. Integer arithmetic in Fortran can lead to other weird surprises - for
instance, the distributive law of division is invalid, as demonstrated by the example
Most of the built-in functions in Fortran apply to real numbers, and attempts to
apply them to integers result in compiler error messages. The compiler will protest
if you ask Fortran to compute sqrt(5), but it has no problem with sqrt(5.). Likewise,
if you declare N to be an integer variable and ask Fortran to compute sqrt(N) or
cos(N) or log(N), your program will not compile since these functions cannot act
on integers. One way around this problem is to use the intermediate function
real(x) ,
which converts x to a real number (if it is not already one). Then, for example,
The compiler will have no objection if N is an integer variable and you ask Fortran
to compute a composition like sqrt(real(N)) or cos(real(N)).
If you declare that A is an integer and later make the assignment A = 3.45, Fortran
will not complain but it will truncate 3.45 and assign A the value A = 3. Likewise,
if you insert the statement A = sqrt (5.), Fortran will truncate sqrt (5.) =
2.23606801 and deduce that A = 2. But errors such as these are easily avoided if
you are careful to make correct type declaration statements for all variables at the
beginning of your program.
A real number, or more precisely a single precision real number, is written with a
decimal point by Fortran, even when it is a whole number. The sequence of
statements
real x
integer y
x=3
y=3
print *, "x = ", x, " but y = ", y, " - weird!"
x = 3. but y = 3 - weird!
GNU Fortran uses up to 9 digits, not counting the decimal point, to represent real
numbers. It will report that
Fortran can use also scientific notation to represent real numbers. The sequence
"En" attached to the end of a number, where n is an integer, means that the number
is to be multiplied by 10n. Here are various ways of writing the number 12.345:
produce the same result if x already has been declared a single precision real
number. Note that commas are not used in representing numbers; as helpful as they
might be to humans, computers find them unnecessary.
When assigning a value to a double precision variable you should use this D-
scientific notation, as otherwise the value will be read only in single precision. For
example, if A is double precision and you want to assign A the value 3.2, you
should write
A = 3.2D0
instead of just A = 3.2. (See Base 2 Conversion Errors below for more
explanation.)
When a number is input from the keyboard in response to a "read *" command, the
user need not worry about types or input format. Suppose for example that x is
single or double precision, and the user is to enter a value for x in response to the
command "read *, x". If the user enters simply "3" (integer format), GNU Fortran
will change 3 to the proper format (to 3. if x is single precision and to 3D0 if x is
double precision) before assigning it to x. Likewise, if x is double precision and the
user enters 3.1 (single precision format), Fortran converts 3.1 to 3.1D0 before
assigning it to x. (However, with an ordinary assignment statement "x = 3.1" from
within the program, the number is not changed to double precision format before
being assigned to x.)
dble(x) .
There is no way to represent such numbers in base 10 with a finite number of digits
without making a round-off error. Computers have the same problem working in
base 2. In general, the only numbers representable with a finite number of digits in
base 2 can be written in the form m/n, where m and n are integers and n is an
integral power of 2. Examples are
program demo
real x
double precision y, z
x = 1.1
y = 1.1
z = 1.1D0
print *, "x =", x, " , y =", y, " , z =", z
end
The somewhat surprising output when this program is run in GNU Fortran is
The variable x is single precision, and base 2 conversion round-off error shows up
in the 9th digit. Although y is double precision, it has the same round-off error as x
because the value 1.1 is assigned to y only in single precision mode. (What
happens is Fortran converts 1.1 to base 2 before changing it to double precision
and assigning it to y.) Since z is double precision, and it is assigned the value 1.1 in
double precision mode, round-off error occurs much later, far beyond the nine
digits in which the results are printed. Thus the value of z prints exactly as it is
received. Using write and format statements (see below), it is possible to print z
using 17 digits; if you do so, you will find that Fortran reports z =
1.1000000000000001, where the final erroneous 1 appears as the 17th digit.
Base 2 round-off error occurs in the preceding example because 1.1 = 11/10, and
10 is not a power of 2. If you modify the program by replacing 1.1 with 1.125 =
9/8, there will be no round-off error because 8 = 23 is a power of 2 - so the values
of x, y, and z will print exactly as assigned. (Try it!!)
If x and y are declared as double precision variables, and you want to multiply x by
a number, say 2.1 for example, to get y, you should write
y = 2.1D0 * x .
Writing just y = 2.1 * x will retain single precision when 2.1 is converted to base 2,
thereby introducing a larger base 2 round-off error and defeating your efforts at
double precision. Similar remarks apply to other arithmetic operations. Errors of
this nature are easily made when working in double precision. The best way to
avoid them is to follow religiously this general rule:
and the integer 5 never enters into the calculations! Thus, although it may appear
so at first glance, the computation of 1.25 does not really mix an integer with a real
number in any arithmetic operation. The same can be said of negative integers as
exponents. The calculation of 1.2-5 involves multiplying five factors of 1.2, and
then taking the reciprocal of the result - so the number -5 is not involved in the
actual arithmetic.
5. ** (2./3.) ,
Roots of numbers are computed in the same manner. To compute the seventh root
of 3 you would use the expression
3. ** (1./7.) .
If N is an integer variable and you wish to compute the N-th root of the real
variable x, do not write x ** (1/N), as Fortran will interpret 1/N as 0 when N > 1.
Instead write x ** (1./real (N)), so that 1 and N are first converted to real variables.
Just as in Basic we use TAB and PRINT USING commands to more precisely
control program output, in Fortran we can use write commands
with format statements. While these can get complicated, the most commonly used
options are pretty easy to use. A typical write statement is
write (*,20) x, y, z .
The "*" in the parentheses instructs Fortran to write to the screen, while "20" refers
to the label of the format statement for this write command. The x, y, and z are the
variables to be printed. A format statement for thiswrite command might be
20 format (3f10.4) .
Inside the parentheses, the "3" indicates that 3 entities will be printed, the "f"
denotes that these will be floating point real numbers (not exponential notation),
the "10" stipulates that 10 places will be used for printing (counting the sign,
decimal point, and the digits), and ".4" mandates 4 digits after the decimal point.
Some printouts formatted this way are
The letter "f" in this context is a format code letter; here are some of the more
commonly used format code letters, with their implications:
i integer
x space
t tab indicator
Strings (in quotes) may be placed in format statements, separated by commas. Here
are examples of write statements with corresponding format statements; at the right
of each is a description of the corresponding output:
You can use loops with format statements to print arrays; here are examples:
write (*,90) (a(i), i = 1, 10) same output as above, except that all
90 format (10f5.2) entries are printed on the same line
1. If you do not specify a format, GNU Fortran will print real numbers using
about 9 digits, even if you do calculations in double precision. If you want
to print in double precision you must use write and format statements. When
double precision is used the maximum number of digits possible is 17. A
format specifier something like format (fm.n), where m is at least 20, is
required to take full advantage of double precision.
2. If a value is too large to be printed in the specified format, Fortran will just
print a string of asterisks (eg: ********** ). If you get such an output, you
have to fix your format statement.
3. Real numbers are rounded off (not truncated) to fit the specified formatting.
4. If your formatting specifies more positions than the number requires, blanks
are inserted to the left of the number.
5. Format statements may appear anywhere in a program after the variable
declarations and before the end statement.
6. Unless your format statement is very simple, the chances are that your
output won't look like you want on the first try - just fiddle with the
formatting until you get it right.
Following are examples of stored values, formatting specifications for printing the
values, and resulting output. (The "^" symbol indicates a blank).
Stored Value Format Specifier Output
-12345 i5 *****
-12345 i6 -12345
12345 i6 ^12345
aloha a8 ^^^aloha
FORTRAN LESSON 4
Lesson Topics
#1#2#3#4#5#6 #1#2#3#4#5#6
Statement Functions
You may replace f with any name you like for your function, and x, y, z, … with
your own variable names. Instead of formula type the formula for your function.
Examples :
area(r) = pi * r * r
vol(r,h) = pi * r * r * h
f(x,y,z) = sqrt(x / y) * cos(z)
You should declare a type for the function in a declaration statement. Here is a
program using a statement function, named "area", to compute areas of circles; the
program computes in double precision the area of an annulus of inner radius a and
outer radius b:
program annulus
double precision r, area, pi, a, b
parameter (pi = 3.1415926535897932D0)
area(r) = pi * r * r
print *, "Enter the inner and outer radii of the annulus: "
read *, a, b
write (*,10) "The area of the annulus is ", area(b) - area(a)
10 format (a,f25.15)
end
In the type declaration statement just include the name of the function - do not
include the parentheses or the function variables.
Observe that variables plugged into the function need not be the same variables
used in defining the function.
But this second function definition must appear later in the program than the first
one.
Continuation Lines
Sometimes a Fortran statement will not all fit into columns 7-72. In such a case
you may continue the statement onto the next line by placing a character in column
6 of that next line. Although any character is allowed, most programmers use "+",
"&", or a digit (using 2 for the first continuation line, 3 for another if necessary,
and so on).
Example :
Do While Loops
Sign Function
The function sign in Fortran is called the sign transfer function. It is a function of
two variables, and its definition involves two cases:
CASE 1: If y ≥ 0 then
sign(x,y) = abs(x) ,
CASE 2: If y < 0 then
sign(x,y) = - abs(x) .
The practical effect is that sign(x,y) has the same absolute value as x, but it has the
same sign as y; thus the sign of y is transferred to x. (The case y = 0 is a little
special - it gives sign(x,y) always a plus sign.)
Examples :
The variables x and y in sign(x,y) may be integers or real numbers, and either
single or double precision. (And x and y may even be of different types.)
If we substitute x = 1 in the sign transfer function, we get the sign of y; that is,
CASE 1: If y ≥ 0 then
sign(1,y) = 1 ,
CASE 2: If y < 0 then
sign(1,y) = - 1 .
Thus, sign(1,y) in Fortran is essentially the same as the function SGN(y) in Basic
(except when y = 0, when the Fortran value is + 1 but the Basic value is 0).
Calculus Computer
Lab
Math 190
News
FORTRAN LESSON 5
Lab Schedule
Arrays
There are only a few minor differences in the way Fortran and Basic treat arrays.
Array declarations in Fortran go at the beginning of the program, before any
executable statement. Arrays can be declared with either adimension statement or a
type declaration. The latter way is preferred, because it is best anyway to declare
the type of the array. Here are examples of arrays introduced by type declarations:
one-dimensional arrays a and b of
real a(10), b(5) real variables, indexed from 1 to 10
and from 1 to 5, respectively
Because arrays are declared at the beginning of the program, they must be given a
fixed size - i.e., the limits must be constants rather than variables. (In this respect
Fortran is less flexible than Basic, in that Basic allows the dimension of an array to
be a variable whose value can be input by the user, thereby ensuring that exactly
the right amount of storage space is reserved.) You don't have to use the full size of
the array specified in the declaration statements; that is, you may reserve space for
more entries in the array than you will need.
If you use a dimension statement to declare an array, you should precede it with a
type declaration. Here is one way to introduce a real array weights, indexed from 1
to 7:
real weights
dimension weights(7)
But the same can be accomplished more briefly with the single statement
real weights(7) .
Although the upper and lower limits of an array cannot be variables, they can be
constants declared in parameter statements. The sequence of statements
integer max
parameter (max = 100)
character names(max)*30
real scores(max)
instructs Fortran to set aside storage space for a list of at most 100 names, each a
string of length no longer than 30 symbols, as well as a list of at most 100 scores,
each a real number.
As in Basic, in Fortran you may input and print arrays with do loops. But you can
sometimes more efficiently do the same with single statements. For instance, the
above array weights can be input with only the statement
read *, weights .
This read statement pauses the program to allow the user to enter all seven entries
of the array. The user can either enter the seven weights one-by-one separated by
returns, or alternatively, can enter all seven weights separated only by commas,
and then a single return. If you want to input say only the first five weights, you
can do so with the statement
read *, (weights(i), i=1,5) .
print *, weights
prints the seven entries of weights to the screen, while the statement
There are various formatting tricks useful in printing two-dimensional arrays. Here
is one example demonstrating how to print a matrix A having 5 rows and 6
columns of real numbers, with each row of the matrix printed on its own line :
do i = 1, 5
write (*,10) (A(i,j), j = 1,
6)
end do
10 format (6f7.3)
More precise formatting can be accomplished with double loops and tab indicators.
Function Subprograms
The first line of the function subprogram specifies the name of the function, and
lists in parentheses the variables upon which the function depends. The
subprogram has its own type statements, declaring the type of the function itself, as
well as the types of the variables involved in computing the function. Somewhere
in the subprogram there must be a line giving the value of the function. (Above it is
the line "fact = p".) The subprogram concludes with an end statement. In Fortran,
function subprograms do not have to be declared as they do in Basic. The entire
function subprogram appears in the source file after the final end statement of the
main program.
The above factorial subprogram, with variables of integer type, works only for
nonnegative integers no larger than 12, as 13! = 6,227,020,800 exceeds the Fortran
upper limit of 2,147,483,647 for integers. To handle larger integers, the types can
be changed to real or double precision. In GNU Fortran, single precision real type
handles factorials of integers as large as 34, and double precision as large as 170.
The main program (or in fact any subprogram) utilizing a function subprogram
should likewise specify the type of the function. Here is a simple main program
using the above factorial function "fact":
program demofactorial
integer fact, n
print *, "What is n?"
read *, n
print *, "The value of", n, " factorial is", fact(n)
end
A function subprogram may depend on several variables, and it may use an already
defined statement function or a function defined by another function subprogram.
Following is a function subprogram utilizing the above factorial function
subprogram; it computes the Poisson probability function, defined as
P(n,t) = tn e- t / n! ,
function poisson(n,t)
real poisson, t
integer n, fact
poisson = (t ** n) * exp(-t) / fact(n)
end
Note that, as this subprogram references the function "fact", it must declare its
type. Both this subprogram and the factorial subprogram will appear in the source
file following the end statement for the main program. (The order in which the
subprograms are typed makes no difference - just as long as they both follow the
main program.)
Again, in referencing function subprograms one must respect types; for example, if
the main program is to compute poisson(m,s) for some variables m and s, then, in
order to conform to the type declarations in the function poisson, m must first be
declared an integer and s of real type. Oversights will lead to compiler type-
mismatch messages.
Following is a program called "mean" that computes the mean, or average, of a list
containing up to 100 numbers. The main program prompts for the list of numbers,
and then references a function subprogram named "avg" that computes the average.
program mean
real numbers(100), avg
integer m
print *, "How many numbers are on your list?"
print *, "(no more than 100, please)"
read *, m
do i =1, m
print *, "Enter your next number:"
read *, numbers(i)
end do
print *, "The average is", avg(m,numbers)
end
function avg(n,list)
real avg, list(100), sum
integer n
sum = 0
do i = 1, n
sum = sum + list(i)
end do
avg = sum/n
end
Note that both the main program and the subprogram declare the type of the
function "avg". The main program calls the function subprogram with the
arguments "m" and "numbers", and these are substituted into the function
subprogram for the variables "n" and "list". The main program specifies the
dimension of the array "numbers", while the subprogram specifies the dimension
of the array "list". The subprogram does its calculations and returns the value of
"avg" to the main program. For this procedure to work, the types of the variables
"m" and "n" must agree, as well as the types of "numbers" and "list".
A return statement in a function subprogram acts like a stop statement in the main
program; the subprogram is terminated and Fortran returns to where it left off in
the main program. Here is a function subprogram defined on integers n; the value
of the function "demo" is 0 if n ≤ 0, and if n > 0 it is the sum of the squares of the
integers from 1 to n:
function demo(n)
integer demo, n
demo = 0
if (n .le. 0) return
do i =1, n
demo = demo + i * i
end do
end
FORTRAN LESSON 6
Lesson Topics
#1#2#3#4 #1#2#3#4
Recall that in Basic the default value of a numeric variable is always zero - that is,
if you introduce a numeric variable but do not specify its value, Basic
automatically gives it the value zero. In GNU Fortran the situation is more
confused. A real variable with no value specified will be given a value - but
usually a very small value that is not precisely zero, and sometimes a value that is
not even close to zero. An integer is given the default value 1. This strange
behavior is hardly ever a problem, as usually when the variable is eventually used
in the program it is given an appropriate value by some assignment statement. But
trouble might arise if a forgetful programmer proceeds on the assumption that the
default value is zero, or perhaps neglects to include an assignment statement. If
you are worried about the problem, you can assign values to all your variables at
the beginning of your program - a procedure called "initializing variables". The
easiest way to do this is with ordinary assignment statements, such as "x = 0", or "y
= 2.61", etc. (For programs with a large number of variables a more efficient
method is to use DATA statements; we will discuss these later.)
Mod
Subroutines
A subroutine in Fortran works like a subprogram in Basic, except that you do not
declare a subroutine. Subroutines are typed in the source file after the main
program. A subroutine must have a name, followed by a list of variables in
parentheses. A variable may be of any type, including a character variable, and can
be an array. A subroutine begins with variable declaration statements, just as the
main program.
The main program uses a call statement to call the subroutine. The call statement
has also a list of variables, which are substituted for the subroutine variables. The
subroutine executes, modifying some or all of its variables, which are then
substituted back for the original call variables in the main program. The variables
in the call statement must match the variables in the subroutine according to
number, type, and dimension. (Oversights lead to type-mismatch error messages by
the compiler.)
Here is a simple program named average that prompts the user for two real
numbers, calls a subroutine named avg to average the numbers, and then prints the
average.
program average
real x, y, z
print *, "What are the two numbers you want to average?"
read *, x, y
call avg(x,y,z)
print *, "The average is", z
end
subroutine avg(a,b,c)
real a, b, c
c = (a + b)/2.
end
When the subroutine is called it substitutes x for a, y for b, and z for c. (Although
the user does not input z, GNU Fortran will have given it some default value.)
After the subroutine does its calculations, the new values of a, b, c are substituted
back into the main program for x, y, z. (In this particular subroutine only c
changes, so x and y retain their original values.) After the subroutine completes its
run, action is returned to the statement in the main program immediately following
the call statement.
Just remember that, except for the first statement naming the subroutine and listing
the variables, a subroutine has the same general structure as a main program. It
begins with type and dimension statements, has a main body carrying out the
action, and concludes with an end statement.
The advantage of using subroutines is that the main program can be kept relatively
simple and easy to follow, while nitty-gritty calculations and complex procedures
are shuffled off to various subroutines, each performing a specific task. A well-
written subroutine can be saved in a subroutine "library", to be inserted into other
main programs as the need arises.
A subroutine can call another subroutine, and it can also access a function
subprogram.
subroutine bluesky
print *, "The sky is blue."
end
subroutine prod(A,x,y)
real A(2,2), x(2), y(2)
y(1) = A(1,1) * x(1) + A(1,2) * x(2)
y(2) = A(2,1) * x(1) + A(2,2) * x(2)
end
call prod(B,u,v) ,
where B and u are arrays known to the main program and the product v is to be
computed by the subroutine. Of course the main program will have appropriately
dimensioned these arrays. After the subroutine completes its task and returns
control to the main program, the array v will represent the product Bu.
subroutine check(n,result)
integer n, i, root
character result*9
if (n .eq. 1) then
result = "not prime"
return
end if
root = sqrt(real(n))
do i = 2, root
if (mod(n,i) .eq. 0) then
result = "not prime"
return
end if
end do
result = "prime"
end
The subroutine begins by checking whether n = 1, and if true it sets result = "not
prime" and returns to the main program. If n > 1 the DO LOOP looks at integers
from 2 up to the square root of n, checking whether each is a divisor of n. If and
when it finds such a divisor, it sets result = "not prime" and returns to the main
program. But if no divisor of n is found, the subroutine completes the entire loop
and sets result = "prime". After the subroutine ends, the main program need only
look at the value of result to find out whether n is prime or not prime.
We look in more detail at how variables are substituted for one another in the
calling and execution of a subroutine or function subprogram. Let us suppose for
example that a certain subroutine named "demo" depends on three variables, say a,
b, and c, so that the first line of the subroutine is
subroutine demo(a,b,c) .
Let us assume also that the main program's call statement for this subroutine is
call demo(x,y,z) ,
where x, y, and z are variables from the main program. The types and dimensions
of x, y, and z will have been declared in the main program, and these must match
the types and dimensions of a, b, and c, respectively, as declared in the subroutine.
The values of x, y, and z will have been stored by Fortran in certain memory
locations, designated in the diagram below as triangles:
x→Δ
y→Δ
z→Δ
When the subroutine "demo" is called, Fortran assigns the variable a the same
memory location as x, b the same location as y, and c the same as z:
x→Δ←a
y→Δ←b
z→Δ←c
(This explains why the types and dimensions must match!) Now, as the subroutine
"demo" runs, the variables a, b and c might change to new values. But since x, y,
and z share memory locations with a, b, and c, the values of x, y, and z of course
will have to change simultaneously along with a, b, and c. When the subroutine
terminates and returns control to the main program, a, b, and c then are no longer
active variables, but x, y, and z retain the final values of a, b, and c at the
conclusion of the subroutine.
There is a way to fool Fortran into not changing the value of a calling variable
when the subroutine runs. In the above example, suppose we change the call
statement to
call demo(x,(y),z) .
x→Δ←a
y→Δ
(y) → Δ ← b
z→Δ←c
Calculus Computer
Lab
Math 190
News
FORTRAN LESSON 7
Lab Schedule
Open
The open command is used to open files - that is, it makes files available so that
Fortran can read or write to them. The simplest form of the command is
open (unit = number, file = "name") .
In place of number you insert a positive integer (but not 6) to be used to refer to the
file, and instead of name you insert the name of the file. Here are examples
of open commands:
Fortran uses the unit number to access the file with later read and write statements.
Several files can be open at once, but each must have a different number. There is
one thing to remember about numbering a file - you cannot use the number 6, as
GNU Fortran reserves that number to refer to the screen.
Note that quotes enclose the filename. Also, in specifying a directory path for a
file, you must use double backslashes instead of single ones. Do not put a space on
either side of the colon after the drive letter. If you do not specify a drive or
directory path for a file, or if you specify the same drive upon which GNU Fortran
is installed but without a path, GNU Fortran will by default assume the file is
located on the same drive and in the same directory from where Fortran is running.
If the named file does not already exist, Fortran will create it; if it does exist,
Fortran will replace it. (So don't mistakenly give the file the same name as another
important file!)
Close
The close command is used to close one or more files - examples are
close (5) , close (1, 3, 8) .
The first of these commands closes the file numbered 5, while the second closes
the three files numbered 1, 3, and 8. It is not necessary to close files; all files will
automatically be closed when an end or stop statement is executed. However, in
programs handling large amounts of data it can be prudent to close files before the
end of the program in order to avoid possible memory problems and to increase
efficiency.
The write command is used to write data to a file. For example, the command
write (7,*)
works like a print * command, except that data is written to the file numbered 7
instead of to the screen. The two statements
produce exactly the same output, except that the first writes to the screen and the
second to file number 7. The command "write (7,*)" on a line by itself serves as a
line feed, skipping a line in the file numbered 7 before the next writing to that file.
You can also use write statements in conjunction with format statements to write to
a file; this gives you better control of formatting. In the following, the first number
in "write (7,5)" refers to the file number and the second to the label of the format
statement:
write (7,5) "The solutions are ", x1, " and ", x2
5 format (a,f16.10,a,f16.10)
The "write (7,5)" command works exactly like the similar command "write (*,5)",
except that in the former output is directed to file number 7, and in the latter to the
screen.
Here is a program that finds and prints to a file the divisors of an integer n :
program divisors
c This program finds the divisors of an integer input by the user.
c The divisors are printed to a file.
integer n, k, d(10)
open (unit = 1, file = "divisors")
print *, "Enter a positive integer :"
read *, n
write (1,*) "Here are the divisors of ", n, " :"
k=0
do i = 1, n
if (mod(n,i) .eq. 0) then
k=k+1
d(k) = i
end if
if (k .eq. 10) then
write (1,5) (d(j), j = 1, 10)
k=0
end if
end do
write (1,5) (d(j), j = 1, k)
5 format (10i7)
close (1)
print *, "The divisors are listed in the file 'divisors'. Bye."
end
Note that the program counts the divisors, storing them in an array d, until 10 are
accumulated; then it prints these 10 on a single line, reserving 7 places for each
divisor. It then begins a new count and repeats the procedure until all divisors are
found. The last write statement prints whatever divisors are left over after the last
full line of 10. The close statement, included here for demonstration only, is
unnecessary, as the program is all but finished at that point and the end statement
will automatically close the file anyway.
Suppose for example that a file is numbered 7, and that the first two lines of the
file contain the data (separated by commas)
read (7,*) x, y, z
read (7,*) m, n, first ,
then the program assigns x = 1.23, y = 4.56, z = 7.89, m = 11, n = 13, first =
"Sally". The variables will have to be declared in the program to correspond with
the data assigned them by the read statements. For instance, in the above situation
x, y, and z will have been declared real variables, m and n integers, and "first" a
character variable. Failure to match variable types with data types will most likely
lead to error messages.
It is possible that a program does not know beforehand the length of a file. If data
is being read from a loop, there is a way to exit the loop when all data in the file
has been read, thereby avoiding a program hang-up. One simply modifies
the read statement to something like
read (7,*,end=10) .
This command instructs Fortran to read the next line in the file numbered 7, but to
jump to the statement labelled 10 in the program in the event that the last line in
that file has already been read.
You can also use format specifiers in read statements, but this can be somewhat
tedious and we will not go into the details. As but one example, suppose you want
to make the assignments
n = 77 , x = 123.45 , y = 67.8 ,
where n is an integer and x and y are real variables. Then you may use the read and
format statements
read (7,5) n, x, y
5 format (i2,f5.2,f3.1) ,
and in file number 7 place the corresponding line of data
7712345678 .
Fortran will read and separate the data, insert appropriate decimal points, and
assign it to the variables. But as you can see the method is confusing and perhaps
not worth the effort.
This table lists additional functions intrinsic to Fortran, not already listed in Lesson 1.
Function Description
Save
This command, used in a subprogram, preserves the values of local variables (i.e., variables
used in the subprogram but not listed in the title statement) from one call of the subprogram
to the next. For instance, the statement
save m, z
in a subroutine ensures that in calls after the first run the subroutine remembers the
final values of m and z from the previous run. A save statement by itself,
save ,
preserves the values of all local variables in the subprogram. You cannot save a
listed variable of the subprogram - the compiler will give an error message. (EG: If
a subroutine's first line is "subroutine area(r)", then you cannot save r.)
Common (Blank)
Ordinarily the only information shared between the main program and subprograms are the
values of variables appearing in variable lists. The common statement can be used to share
additional information.
The simplest form of the common statement is the blank common statement. Let us
suppose for illustration that the main program has real variables x and y as well as
an integer variable n which are to be shared with one or more subroutines. Then at
the beginning of the main program, before any executable statements, you first
declare the types of x, y, and n and next insert the "blank common" statement
common x, y, n .
This instructs Fortran to preserve three "common" memory locations for x, y, and
n, designated as triangles below:
x→Δ
y→Δ
n→Δ
These memory locations are then accessible by all subroutines of the program
containing a similar common statement (but with possibly different variables). For
example, suppose a subroutine declares real variables u and v and an integer
variable m. If the subroutine contains also the common statement
common u, v, m ,
x→Δ←u
y→Δ←v
n→Δ←m
When the values of u, v, and m change in the subroutine, then the values of x, y,
and n in the main program change accordingly; and vice-versa - changes in x, y, or
n in the main program produce changes in u, v, and m in the subroutine.
Obviously, because of the sharing of memory locations, the types of x, y, and n
must match those of u, v, and m, respectively (and also dimensions must match in
the case of arrays.)
It is possible for a third or even more subroutines to share the same three memory
locations. If a third subroutine has real variables a and b and an integer variable k,
as well as the statement
common a, b, k ,
A common statement cannot list variables that are listed also in the title statement
of the subprogram in which the common statement appears. (EG: If a subroutine's
first line is "subroutine area(r)", then you cannot list r in the subroutine's common
statement.)
Common (Named)
In programs with more than one subroutine it is sometimes desirable to share different sets of
variables among different sets of program units. In such situations the named
common statement is useful. The general form of this statement is
common / name1 / list1 / name2 / list2 / name3 / list3 / … / nameN / listN .
The "names" are names for the different sets of variables, and the "lists" contain
the names of variables in these sets.
Then the variable set "first" consists of A and B, and is shared by the main
program and demo1. Variable set "second" consists of C and D and is shared by all
three units. Variable set "third" consists of E, F, and G and is shared by the main
program and "demo2". It is not necessary that different units use the same variable
names for shared data. For example, subroutine "demo2" could name its five
variables V, W, X, Y, Z; then its common statement would change to
Data
A data statement is used to initialize (i.e., assign initial values to) variables before the
program begins. All data statements must appear after parameter and type declarations; it is
common practice to include them immediately following these statements.
data list1 / data1 / list2 / data2 / list3 / data 3 / ... / listN / dataN / .
Each list is a list of variables separated by commas, and each data is a list of values
of the variables in the preceding list. Following is a table of examples with the
corresponding resulting assignments:
data k, m, n, p / 3 * 0, 1 / k = m = n = 0, p = 1
Note that in a data list the notation "n * x" means that the value x is to be assigned
to n successive variables in the preceding variable list.
Data statements were necessary in earlier versions of Fortran, when the compiler
did not automatically initialize variables; in more modern versions of Fortran they
can usually be omitted without repercussions.
Arithmetic If
where expression is some numeric expression that Fortran can evaluate, and k, m,
n are integers representing labels of executable statements. If expression is
negative, zero, or positive, then the program jumps to the statement labeled k, m,
or n, respectively. As illustration, a program solving a quadratic equation
ax2 + bx + c = 0
if (b * b - 4 * a * c) 10, 20, 30 .
Then if the discriminant b2 - 4ac is negative, the program jumps to the statement
labeled 10, if it is zero the jump is to label 20, and if positive to label 30.
Computed Go To
where n1, n2, ..., nm are integers representing labels of executable statements,
and integer expression is some integer - valued expression that Fortran can
evaluate. If the value of this expression is 1, the program jumps to the statement
labeled n1, if the value is 2 the program jumps to the statement labeled n2, etc. For
example, suppose a program contains the sequence
If the user enters 1, the program jumps to the statement labeled 10, if the user
enters 2 it jumps to statement 12, if the user enters 3 it jumps to 14, etc. If the user
errs and enters an integer different from 1, 2, 3, 4, 5, 6, Fortran defaults to the first
statement listed, in this case statement 10.