Category Archives: Computing posts

Fortran: Install

To download and install GNU Fortran into Windows, download into your c:\ directory the four files

g77exe.zip g77doc.zip
g77lib.zip unzip.zip .

Get a command prompt and go to the root directory on your c drive by entering

cd c:\

Change the name of unzip.zip to unzip.exe by entering

ren unzip.zip unzip.exe

Next unzip the three zipped files by entering in succession

									unzip g77exe.zip
									unzip g77lib.zip
									unzip g77doc.zip

The three files will unzip into a g77 directory, divided into three subdirectories named g77\bin, g77\lib, and g77\doc.

Fortran is run from the g77\bin directory. It is simplest to save all your Fortran programs to this same directory. To get into this directory from a DOS prompt, enter

									cd c:\g77\bin

Then, to compile for example the file hello.f, enter

g77 hello.f
Fortran creates a compiled file that it names a.exe. To run this file from the g77\bin directory just enter

a

If you want to give the compiled file a name of your own choosing, say such as hello.exe, then compile it with the command

g77 hello.f -o hello.exe

(Any name you give a compiled file must end with the extension .exe.)

On your home computer probably the easiest editor for creating Fortran source files is the DOS editor. Open a DOS window, go to the g77\bin directory (as above), and enter "edit". The DOS editor will open and you can type your source file. When you save the file, just name it whatever.f and it will automatically be saved to the g77\bin directory (by default, since that is the directory from which you opened the DOS editor). You do not have to enclose the name in quotes, as you do in saving with Notepad.

Perhaps the most efficient way of writing and testing a Fortran program on your home computer is to open two DOS windows, one for editing your source file with the DOS editor, and the second for compiling and running your program. In each window you will be working from the g77\bin directory, and you can jump from one window to the other with the click of your mouse.

Remark: This distribution of Fortran was obtained from the now defunct website http://www.geocities.com/Athens/Olympus/5564/g77.htm but the instructions should work (last checked on January 7, 2012).

Fortran: More

Topics


Following is further Fortran information not covered in the lessons.

More Intrinsic Functions

This table lists additional functions intrinsic to Fortran, not already listed in Lesson 1.

Function Description
aint(x) truncates the decimal part of x
(without changing the type of x)
anint(x) rounds x to the nearest integer
(without changing the type of x)
int(x) converts x to integer type, giving it
the value of the integer closest to x
but no larger than x in absolute value
log10(x) common logarithm of x (base 10)
max(x1,x2,...,xn) maximum of x1, x2, ..., xn
min(x1,x2,...,xn) minimum of x1, x2, ..., xn
nint(x) converts x to integer type,
rounding x to the nearest integer

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    ,

then u, v, and m will share memory locations with x, y, and n, respectively :
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    ,

then x, u, a share one memory location, y, v, b another, and n, m, k a third. A change in one of these variables in the main program or a subroutine produces the same change in whatever variables share the same memory location.
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.
Suppose, for example, that the main program uses variables A, B, C, D, E, F, G, while subroutine "demo1" uses variables A, B, C, D, and subroutine "demo2" uses variables C, D, E, F, G. If we want all program units using the same variable to share the value of that variable, then in the main program we insert the named common statement
common / first / A, B / second / C, D / third / E, F G     ,

in subroutine "demo 1" we insert
common / first / A, B / second / C, D    ,

and in "demo 2" we insert
common / second / C, D / third / E, F, G    .

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
common / second / V, W / third / X, Y, Z     ,

and consequently V and C would share a memory location, as would W and D, X and E, Y and F, and Z and G.

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.
The general form of a data statement is
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 x, y, z / 2.1, 3.3, -4.4 / x = 2.1, y = 3.3, z = - 4.4
data k, m, n, p / 3 * 0, 1 / k = m = n = 0, p = 1
data first, last / "Jane", "Smith" / first = "Jane", last = "Smith"
data A / 5.2 / B, C / 2.8, 3.9 / A = 5.2, B = 2.8, C = 3.9
data x, y / 2*1. / m,n / 2*0 / pi / 3.14 / x = y = 1., m = n = 0, pi = 3.14

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

The arithmetic if statement has the form

if (expression) k, m, n     ,

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

might have the arithmetic if statement
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

The computed go to statement has the form
go to (n1 , n2 , ..., nm) integer expression    ,

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
print *, "Enter the number of the task you want to perform:"
read *, n
go to (10,12,14,16,18,20) n

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.

Fortran: Lesson 7

Lesson topics


View Demos
#1 #2 #3
Download Demos
#1 #2 #3

Sometimes it is convenient in a Fortran program to use files for accessing or storing data - especially when large amounts of data are involved. Too much keyboard input during the run of a program leads to mistakes and tedium, while too much screen output has similar consequences. Putting data into files - both for input and output - is a more leisurely and less error-prone approach.

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:
									open (unit = 2, file = "scores")
									open (unit = 7, file = "a:scores.txt")
									open (unit = 5, file = "h:\\results\\primes")
									open (unit = 24, file = "c:\\fortran\\data\\divisors.dat")

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.

Write (to Files)

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
									print *, "The solutions to the equation are : ", x1, x2
									write (7,*) "The solutions to the equation are : ", x1, x2

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.
Each execution of a write command writes to a single line in a file. The next write command will write to a new line.
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.

Read (from Files)

The read statement is used to read data from a file. Generally data is read from a file in the standard way, line-by-line and from left to right. But you must remember that each read statement begins reading a new line, whether or not the preceding read statement used all the data in the preceding line.
Suppose for example that a file is numbered 7, and that the first two lines of the file contain the data (separated by commas)
1.23 , 4.56 , 7.89
11, 13 , "Sally"

If the first two read statements in the program are
									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.

Fortran: Lesson 6

Lesson topics


View Demos
# 1 # 2 # 3 # 4
Download Demos
# 1 # 2 # 3 # 4

Initializing Variables

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

In Fortran the expression mod(n,m) gives the remainder when n is divided by m; it is meant to be applied mainly to integers. Examples are
mod(8,3) = 2   ,   mod(27,4) = 3   ,   mod(11,2) = 1   ,   mod(20,5) = 0  .

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.
A subroutine need not depend on any variables - in which case no parentheses follow the subroutine name. Here is a simple subroutine involving no variables:
									subroutine bluesky
									print *, "The sky is blue."
									end
The call statement for this subroutine,
									call bluesky
likewise lists no variables.
The following subroutine computes the product of a 2 x 2 matrix A with a 2 x 1 vector x, according to the formula
matmult

It accepts as variables a 2 x 2 array A and one-dimensional arrays x and y, each indexed from 1 to 2. The array y represents the product y = Ax.
									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
A call statement for this subroutine might be something like
									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.

Return (in Subroutines)

A return statement in a subroutine instructs Fortran to terminate the subroutine and return to the main program at the point where it departed. Thus it works like a stop statement in the main program, halting the program prematurely before the final end statement. A subroutine may have several returns, but only one end statement.
Here is a subroutine, using a return statement, that decides whether a positive integer n is a prime number:
									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.

Variable Substitution in Subprograms

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

When the variable y is enclosed in parentheses, Fortran treats (y) as a new expression and assigns it a different memory location than that of y, but with the save value as y. The last diagram changes to
x → Δ ← a
y → Δ
(y) → Δ ← b
z → Δ ← c

Now, as b changes values during the execution of the subroutine, y is unaffected, so that at the conclusion of the subroutine y has its original value.
The above analysis applies to function subprograms as well as to subroutines. Changes in the function variables during execution of a function subprogram induce corresponding changes in the variables used to call the function subprogram.