Category Archives: Undergrad posts

Fortran: Lesson 5

Lesson topics


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

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 a dimension 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:
real a(10), b(5) one-dimensional arrays a and b of
real variables, indexed from 1 to 10
and from 1 to 5, respectively
integer n(3:8), m one-dimensional array n of integers,
indexed from 3 to 8, and an integer
variable m
double precision c(4,5) two-dimensional array c of double
precision real numbers, the first
index running from 1 to 4, and the
second from 1 to 5
character student(30)*20 one-dimensional array student of
strings, indexed from 1 to 30, each
string up to 20 symbols long
real num(0:5,1:10,-3:3) three-dimensional array num of single
precision real numbers, the first index
running from 0 to 5, the second from
1 to 10, and the third from -3 to 3

In Fortran the default lower limit of the range of a subscript is 1, rather than 0 as in Basic. A colon separates the lower and upper limits whenever both are specified.
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)   .

Analogously, the single print statement
print *, weights

prints the seven entries of weights to the screen, while the statement
print *, (weights(i), i=p,q)

prints only the weights indexed from p to q.
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

Function subprograms in Fortran define functions too complicated to describe in one line. Here is a function subprogram defining the factorial function, fact(n) = n! :
function fact(n)
integer fact, n, p
p = 1
do i = 1, n
p = p * i
end do
fact = p
end

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

Because n is declared an integer in the function subprogram defining fact(n), it must also be an integer in the main program when fact(n) is evaluated; if it is of a different type the compiler displays a type mismatch error message.
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!   ,

where n is a nonnegative integer and t any positive number:
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.

Arrays in Function Subprograms

An array can be listed as a variable of a function defined by a function subprogram - but you just write the array name, with no parentheses after the name as in Basic. The type and dimension of the array must be specified in the function subprogram.
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".

Return (in Function Subprograms)

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 4

Lesson topics


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

Statement Functions

A statement function in Fortran is like a single line function definition in Basic. These are useful in defining functions that can be expressed with a single formula. A statement function should appear before any executable statement in the program, but after any type declaration statements. The format is simple - just type
f(x,y,z,…) = formula   .

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.
It is possible to use a previous statement function in the definition of another. In the above program, for example, we have already defined the function area(r), so we could define further a second function "annarea", giving the area of the annulus as
								  annarea(a,b) = area(b) - area(a)

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 :
det = a(1,1) * a(2,2) * a(3,3) + a(1,2) * a(2,3) * a(3,1)
& + a(2,1) * a(3,2) * a(1,3) - a(3,1) * a(2,2) * a(1,3)
& - a(2,1) * a(1,2) * a(3,3) - a(1,1) * a(3,2) * a(2,3)

Do While Loops

A do while loop in Fortran is similar to the same loop in Basic. However, in Fortran the test must be enclosed in parentheses, and the end of the loop is identified with either end do or a labeled continue statement. As in "if … then" constructions, in loop tests one uses letter abbreviations for relations such as "≤", ">", "=", etc. Here are two loops adding the squares of the integers from 1 to 10; they differ only in the way the loops are terminated:
N = 1 | N = 1
S = 0 | S = 0
do while (N .le. 10) | do 5 while (N .le. 10)
S = S + N ** 2 | S = S + N ** 2
N = N + 1 | N = N + 1
end do | 5 continue

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 :
sign(2,3) = 2   ,   sign(2, -3) = - 2   ,   sign(-2,3) = 2   ,   sign(-2, -3) = - 2   .

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

Fortran: Lesson 3

Lesson topics


View Demos
# 1 # 2 # 3 # 4 # 5 # 6 # 7 # 8 # 9
Download Demos
# 1 # 2 # 3 # 4 # 5 # 6 # 7 # 8 # 9

In Fortran Lesson 1 we briefly looked at the types of variables in Fortran. To avoid mistakes in Fortran arithmetic you must pay close attention to rules regarding working with numbers of the various types. Whereas Basic is more lenient, allowing some flexibility in mixing variables and numbers of different types, Fortran is less forgiving and will make you pay for oversights. In this lesson we look more closely at some of the rules and conventions that must be observed.

Integers

An integer in Fortran is a whole number; it cannot contain commas or a decimal point. Examples of numbers considered integers by Fortran are
12    ,     -1311     ,     0     ,     +43     ,     123456789     .

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
22,547     ,     3.     ,     4.0     ,     -43.57 .

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  .

One idiosyncrasy of Fortran is that when it performs arithmetic on integers, it insists on giving an answer that is likewise an integer. If the answer is not really an integer, Fortran makes it one by discarding the decimal point and all digits thereafter. For example, Fortran will assert that
11/8 = 1    ,    15/4 = 3    ,    -4/3 = -1    ,    -50/6 = -8    ,    2/3 = 0   .

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
(2 + 3)/4 = 5/4 = 1     but     (2/4) + (3/4) = 0 + 0 = 0   .

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,
real(5) = 5.    ,    sqrt(real(5)) = sqrt(5.) = 2.23606801  .

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.

Single Precision Real Numbers

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!"

produces the output

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
sqrt (3.) = 1.73205078   ,   sqrt (1100.) = 33.1662483   ,   sqrt (2.25) = 1.5   .

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:
1.2345E1  ,  .12345E2  ,  .012345E3  ,  12.345E0  ,  12345E-3  .

In working in single precision it is futile to assign more than 9 or 10 nonzero digits to represent a number, as Fortran will change all further digits to 0. (The 10th digit can affect how Fortran does the truncation.) The assignments
									x = 123456789876543.
									x = 123456789800000.
									x = 1234567898E5

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.

Double Precision Real Numbers

A double precision real number in GNU Fortran can be represented by up to 17 digits before truncation occurs. Double precision numbers are written in scientific notation but with D usurping the role of E. Some various ways of writing the number 12.345 as a double precision real number are

1.2345D1  ,  .12345D2  ,  .012345D3  ,  12.345D0  ,  12345D-3 .

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.)
A number x can be converted to double precision by the function
dble(x)   .

Base 2 Conversion Errors

Whereas humans, having 10 fingers, do arithmetic in base 10, computers have no fingers but do arithmetic with on-off switches and therefore use base 2. As we know, some numbers have infinite decimal representations in base 10, such as
1/3 = .33333 …       ,       2/7 = .285714285714 …   .

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
6 (= 6/20)   ,   5/2   ,   3/8   ,   29/16   ,   537/256   ,   -3/1024 .

When we ask computers to do arithmetic for us, there is an inevitable source of error. We give the computer the numbers in base 10, and the computer must change them all over to base 2. For most numbers there is a round-off error, as the computer can work with only a finite number of digits at a time, and most numbers do not have a finite representation in base 2. If the computer is working in single precision Fortran, it works in about 9 digits (base 10), and so the round-off error will occur in about the 8th or 9th base 10 digit. In double precision this error appears much later, in about the 16th or 17th base 10 digit. If the arithmetic the computer performs is very complicated, these round-off errors can accumulate on top of each other until the total error in the end result is much larger. After the computer has done its job in base 2, it converts all numbers back to base 10 and reports its results.
Even if the computer does no arithmetic at all, but just prints out the numbers, the base 2 conversion error still appears. Here is a program illustrating the phenomenon:
									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
x = 1.10000002   ,   y = 1.10000002   ,   z = 1.1   .

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

Mixed Type Arithmetic

In general, arithmetic in Fortran that mixes numbers of different types should be avoided, as the rules are quickly forgotten and mistakes are easily made. If Fortran is asked in some arithmetic operation to combine an integer number with a real one, usually it will wait until it is forced to combine the two and then convert the integer to real mode. Here are some calculations illustrating the process followed by Fortran, and showing why you should stay away from this nonsense:
5. * (3 / 4) = 5. * 0 = 5. * 0. = 0.
(5. * 3) / 4 = (5. * 3.) / 4 = 15. / 4 = 15. / 4. = 3.75
5. + 3 / 4 = 5. + 0 = 5. + 0. = 5.
5 + 3. / 4 = 5 + 3. / 4. = 5 + .75 = 5. + .75 = 5.75

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:
Do not mix numbers of different types in Fortran arithmetic!!

Exponentials and Roots

Already we point out an exception to the above rule - it is OK to use integers as exponents of real numbers. That is because, when serving as an exponent, an integer acts more as a "counter of multiplications" rather than as an active participant in the arithmetic. For instance, when Fortran does the calculation 1.25, it performs the multiplications
1.2 * 1.2 * 1.2 *1.2 * 1.2   ,

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.
Rational exponents must be handled carefully. A common mistake of novice Fortran programmers is to write something like 5 ** (2/3) and expect Fortran to compute the value of 52/3. But Fortran will view 2 and 3 as integers and compute 2/3 = 0, and conclude that 5 ** (2/3) = 5 ** 0 = 1. The correct expression for computing 52/3 is
5. ** (2./3.)   ,

wherein all numbers are viewed as real numbers.
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.

Write and Format Statements

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 this write 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
12345.6789    ,    -1234.5678    ,    10002.3400   .

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:
freal number, floating point format
esingle precision real number, exponential notation
ddouble precision real number, exponential notation
iinteger
atext string (character)
xspace
/vertical space (line feed)
ttab 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:
       write (*,10) n, x, y
10   format (i4,4x,f10.4,2x,f10.4)
integer n printed using 4 places,
then 4 spaces, then real numbers
x and y printed with 2 spaces
between, each using 10 places
and 4 decimal places
       write (*,20) area
20   format ("The area is ",f8.5)
string in quotes is printed, then the
real number area is printed, using
8 places with 5 decimal places
       write (*,30) "The area is ", area
30   format (a,f8.5)
same output as immediately above
       write (*,40) x, y, z
40   format (3d20.14)
3 double precision numbers x, y, z
printed, each reserving 20 spaces,
with 14 decimal places
       write (*,50) student, score
50   format (a20,4x,i3)
student, a text string up to 20
characters, is printed, then 4
spaces, then score, an integer
using a maximum of 3 places
       write (*,60) r, A
60   format (t10,f4.2,/,t10,f6.2)
tabs to column 10, prints real
number r, goes to next line, tabs to
column 10, prints real number A

You can use loops with format statements to print arrays; here are examples:
       do i = 1, 10
          write (*,70) a(i)
       end do
70   format (f5.2)
an array a of real numbers,
indexed from 1 to 10, is printed;
each entry occupies 5 places with
2 decimal places, and is printed
on a separate line
       write (*,80) (a(i), i = 1, 10)
80   format (f5.2)
same output as immediately above
       write (*,90) (a(i), i = 1, 10)
90   format (10f5.2)
same output as above, except that all
entries are printed on the same line
       do i = 1, 5
           write (*,7) (m(i,j), j = 1, 6)
7         format (6i3)
       end do
prints a 5 x 6 two-dimensional array
m of integers, with each integer entry
m(i,j) occupying 3 places. Each row
of the matrix appears on its own line.

Here are other useful things to know about formatting:

  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
1.234567f8.2^^^^1.23
0.00001f5.30.000
-12345i5*****
-12345i6-12345
12345i6^12345
0.00001234e10.3^0.123E-04
0.0001234e12.4^^0.1234E-03
1234567.89e9.2^0.12E+07
alohaa8^^^aloha
1.23456789123D0d17.10^0.1234567891E+01

Fortran: Lesson 2

Lesson topics


View Demos
# 1 # 2 # 3 # 4 # 5 # 6 # 7 # 8 # 9 # 10
Download Demos
# 1 # 2 # 3 # 4 # 5 # 6 # 7 # 8 # 9 # 10

We look at more of the commonly used features and commands of Fortran.

Logical Expressions

A logical expression is a relation between variables or expressions that can have a value of TRUE or FALSE. Such expressions are used in "if Ö then" constructions and in loops, when testing whether to execute certain steps of a program. Relations and connectives appearing in logical expressions are listed in the following table; you will see how some of these are used in later examples.

Relation/Connective   Meaning
.lt. less than
.gt. greater than
.le. less than or equal to
.ge. greater than or equal to
.eq. equals
.ne. not equal to
.and. and
.or. or
.not. not
.xor. "exclusive" or (i.e., only one is true)
.eqv. equivalent (i.e., same truth values)
.neqv. not equivalent

If ... Then ... Else Constructions

"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"
  2. if (x .ge. y .and. x .ge. z) go to 40
  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 .ge. 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

indicates that "name" is a character variable holding no more than 20 symbols, while "ans" is a character variable holding only one symbol.

A string in Fortran may be enclosed in either double quotes, as in "hello", or in single quotes, as in 'goodbye'.

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
										do i = 1, 10
											sum = sum + i ** 2
										end do
										print *, "The sum is", sum
									sum = 0
									do 5 i = 1, 10
									sum = sum + i ** 2
								5	continue
									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 j = 1, 10
												a(i,j) = i + j
											end do
										end do
									do 5 i = 1, 10
									do 5 j = 1, 10
									a(i,j) = i + j
								5	continue