You are on page 1of 10

3.

1 INTRODUCTION TO TOP-DOWN DESIGN TECHNIQUES


Suppose that you are an engineer working in industry, and that you
need to write a
Fortran program to solve some problem. How do you begin?
When given a new problem, there is a natural tendency to sit do
wn at a terminal
and start programming without "wasting" a lot of time thinking about it
first. Tt is often
possible to get away with this on-the-fly approach to programming
for very small
problems, such as many of the examples in this book. In the real world,
however, prob
lems are larger, and a programmer attempting this approach will bec
ome hopelessly
bogged down. For larger problems, it pays to completely think out the p
roblem and the
approach you are going to take to it before writing a single line of cod
e.
We will introduce a formal program design process in this section,
and then apply
that process to every major application developed in the remainder o
f the book. For
some of the simple examples that we will be doing, the design process
will seem like
overkill. However, as the problems that we solve get larger and lar
ger, the process
becomes more and more essential to successful programming.
When I was an undergraduate, one of my professors was
fond of saying,
"Programming is easy. It's knowing what to program that's hard." His p
oint was force
fully driven home to me after I left university and began working in ind
ustry on largerscale software projects. I found that the most difficult part of my job wa
s to understand
the problem I was trying to solve. Once I really understood the pro
blem, it became
easy to break the problem apart into smaller, more easily manageable pi
eces with welldefined functions, and then to tackle those pieces one at a time.
Top-down design is the process of starting with a large task and
breaking it down
into smaller, more easily understandable pieces (subtasks) that perfor
m a portion of
the desired task. Each sobtask may in turn be subdivided into smaller
subtasks if nec
essary. Once the program is divided into small pieces, each piece ca
n be coded and
tested independently. Wc do not attempt to combine the subtasks into
a complete task
until each of the subtasks has been verified to work properly by itself.
The concept of top-down design is the basis of our formal
program design pro
cess. We will now introduce the details of the process, which is illus

trated in Figure
3-1. The steps involved are as follows:

1. Clearly state the problem that you are trying to solve.


Programs are usually written to fill some perceived need, but th
a t need may not
be articulated clearly by the person requesting the program. For exam
ple, a user may
ask for a program to solve a system of simultaneous linear equations.
This request is
not clear enough to allow a programmer to design a program to meet the need; he or
she must first know much more about the problem to be solved. Is the system of equa
tions to be solved real or complex? What is the maximum number of equations and
unknowns that the program must handle? Are there any symmetries in the equations
that might be exploited to make the task easier? The program designer will have to talk
with the user requesting the program, and the two of them will have to come up with
a clear statement of exactly what they are trying to accomplish, A clear statement of
the problem will prevent misunderstandings, and it will also help the program designer
to properly organize his or her thoughts. In the example we were describing, a proper
statement of the problem might have been:
Design and write a program to solve a system of simultaneous linear equa
tions having leal coefficients and witli up to 20 equations in 20 unknowns.

2. Define the inputs required by the program and the outputs to be produce
d by

the program.

The inputs to the program and the outputs produced by the program m
ust be
heme.
ably in
in that
at may
ormat

specified so that the new program will properly fit into the overall processing sc
In the above example, the coefficients of the equations to be solved are prob
some pre-existing order, and our new program needs to be able to read them
order. Similarly, it needs to produce the answers required by the programs th
follow it in the overall processing scheme, and to write out those answers in the f
needed by the programs following it.

3. Design the algorithm that you intend to implement in the program


An algorithm is a step-by-step procedure for finding the solution to a
problem.
y. The
tasks
elves

It is at this stage in the process that top-down design techniques come into pla
designer looks for logical divisions within the problem, and divides it up into sub
along those lines. This process is called decomposition. If the subtasks are thems
large, the designer can break them up into even smaller sub-subtasks. This

process
which

continues until the problem has been divided into many small pieces, each of

does a simple, clearly understandable job.


After the problem has been decomposed into small pieces, each piece

is fur

ther refined through a process called stepwise refinement. In stepwise refine

ment, a

designer starts with a general description of what the piece of code should do, an

d then

defines the functions of the piece in greater and greater detail until they are s
pecific

enough to be turned into Fortran statements. Stepwise refinement is usually done

with

pseudocode, which will be described in the next section.


It is often helpful to solve a simple example of the problem by hand du

ring the

algorithm development process. A designer who understands the steps that he

or she

went through in solving the problem by hand will be better able to apply deco
mposi

tion and stepwise refinement to the problem.

4. Turn the algorithm into Fortran statements.


If the decomposition and refinement process was carried out properly, this
step

will be very simple. All the programmer will have to do is to replace pseudocod

e with

the corresponding Fortran statements on a one-for-one basis.

5. Test the resulting Fortran program.


This Step is the real killer. The components of the program must first be
tested
individually, if possible, and then the program as a whole must be tested. When t
esting

a program, we must verify that it works correctly for all legal input data sets. It i

s very

common for a program to be written, tested with some standard data set, and rel

eased

for use, only to find that it produces the wrong answers for crashes) with a d

ifferent

input data set. If the algorithm implemented in a program includes different bran
ches,

we must test all of the possible branches to confirm that the program operates cor

rectly

under every possible circumstance.


Large programs typically go through a series of tests before they are releas

ed for

general use (see Figure 3-2). The first stage of testing is sometimes called uni

t test

ing. During unit testing, the individual subtasks of the program are tested separate
ly

3.4.1 The Block IF Construct


The commonest form of the I F statement is the block I F construct. This construct
specifies that a block of code will be executed if and only if a certain logical expres
sion is trae. The block IF constract has the fomi
TF

(1ngica]_expr)
Statement
Statement

1
2

THFN
Code

Block

END

IF

If the logical expression is true, the program executes the statements in the block
between the IF and END IF statements. If the logical expression is false, then llie pro
gram skips all of the statements in the block between the IF and END IF statements,
and executes the next statement after the END IF. The flowchart for a block 1F con
struct is shown in Figure 3-5.
The IF (...) THEN is a single Fortran statement that must be written all
together on the same line, and the statements to be executed must occupy separate
lines below the I F (...) THEN statement. An END IF statement must follow the
m
on a separate line. There should not be a statement number on the line containing
the END IF statement. For readability, the block of code between the IF and END
I F statements is usually indented by two or three spaces, but this is not actuall
y
required.

3.6.1 Summary of Good Programming Practice


The following guidelines should be adhered to in programming with branch o

r loop

constructs. By following them consistently, your code will contain fewer bugs, w

ill be

easier to debug, and will be more understandable to others who may need to wor

k with

it in the future.
1. Always indent code blocks in block IF and CASE constructs to make the
m more
2.
, since

readable.
Be cautious about testing for equality with real variables in an IF construct
round-off errors may cause two variables that should be equal to fail a

test for

equality. Instead, test to see if the variables are nearly equal within the rou

nd-off
3.
logical

error to be expected on the computer you are working with.


Always include a DEFAULT CASE clause in your case constnicts to trap any
errors or illegal inputs that might occur in a program.

4.1
CONTROL CONSTRUCTS: LOOPS
Loops are Fortran constracts that permit us to execute a sequence of statements more
than once. There are two basic forms of loop constructs: while loops and iterative
loops (or counting loops). The major difference between these two types of loop is
in how the repetition is controlled. The code in a while loop is repeated an indefinite
number of times until some user-specified condition is satisfied. By contrast, the code
in an iterative loop is repeated a specified number of times, and the number of repeti
tions is known before the loop starts.

4.1.2

The DO

WHILE Loop

There is an alternative form of the while loop in Fortran 95/2003, called the DO WHILE
loop. The DO WHI LE construct has the form

DO WHILE (logicdl_expr)

END DO

"I
I

Statement 1
Statement 2

Statement n

If the logical expression is true, statements 1 through n will be executed, and then con
trol will return to the DO WHILE statement. If the logical expression is still taic, the state
ments will be executed again. This process will be repeated until the logical expression
becomes false. When control returns to the DO WHILE statement and the logical expres
sion is false, the program will execute the first statement after the END DO.
This construct is a special case of the more general while loop, in which the exit
test must always occur at the top of the loop. There is no reason to ever use it, since the
general while loop does the same job with more flexibility.

4.1.3 The Iterative or Counting Loop


In the Fortran language, a loop that executes a block of statements a specified number
of times is called an iterative DO loop or a counting loop. The counting loop constnict
has the form

DO index = istart,
Statement 1

iend. incr
1
> Code Block

Statement n
J
END DO
where 1 ndex is an integer variable used as the loop counter (also known as the loop
index). The integer quantities i start, iend, and incr are the parameters of the
counting loop; they control the values of the variable i ndex during executi
on. The
own as
oop.

parameter i ncr is optional; if it is missing, it is assumed to be 1.


The statements between the DO statement and the END DO statement are kn
the body of the loop. They are executed repeatedly during each pass of the DO l
The counting loop construct functions as follows:
1, Each of the three DO loop parameters i start, i end, and i ncr may be a

constant,

a variable, or an expression. If they are variables or expressions, then their

values

are calculated before the start of the loop, and the resulting values are

used to
2.
he value

control the loop.


At the beginning of the execution of the DO loop, the program assigns t
i start to control variable index. If i n d e x *! ncr

ram ex

<

i e n d * i n c r, the prog

3.
l vari

ecutes the statements within the body of the loop.


After the statements in the body of the loop have been executed, the contro
able is recalculated as
index =

index +

incr

If 1 ndex*incr is still < iend*i ncr, the program executes the statements
within
4.
hen this

the body again.


Step 2 is repeated over and over as long as i ndex*1 ncr < i end*1 ncr. W
condition is no longer true, execution skips to the first statement following th

e end

of the DO loop.

6.1
DECLARING ARRAYS

Before an array can be used, its type and the number of eleiueuts it contains m
ust
be declared to the compiler in a type declaration statement, so that the compiler will
know what sort of data is to be stored in the array, and how much memory is require
d
to hold it. For example, a real array voltage containing 16 elements could be declare
d
as follows,'
REAL,

DIHENSI0N(16)

::

voltage

The DIMENSION attribute in the type declaration statement declai-es the size of the array
being defined. The elements in array vol tag e would be addressed as v o l t a g e ( l )
,
' An alternative
way to declare an array is to attach the dimension information directly to the array name:

REAL ::

voltage(16)

This declaration style is provided for backward compatibility with earlier versions of Fortran. It is full
y
equivalent to the array declaration shown above.

vol tage(2), etc., u p t o v o l t a g e ( 1 6 ) . Similarly, an array of fifty 20character-long

variables could be declared as follows:


CHARACTERden

20),

DIMENSIDN(50)

::

last.name

Each of the elements in array 1 ast_name would be a 20-character-long variab


le, and
the elements would be addressed as 1 ast_nanie( 1), 1 ast_narne( 2), etc.
Arrays may be declared with more than one subscript, so they may be org
anized

into two or more dimensions. These arrays are convenient for representing data t

hat is
normally organized into multiple dimensions, such as map information, tempe
rature
d for a
st_naniip

measurements on a flat surface, and so forth. The number of subscripts declare


given array is called the rank of the array. Roth array vol tagp and array 1 a .
are rank 1 arrays, since they have only one subscript. We will see more complex

arrays

ent of
vul
50. The
e array
e rank
umber
y is the
is 20,
consist
between
Fortran
r is / ).
g five

later in Chapter 8.
The number of elements in a given dimension of an array is called the ext
llie array in thai dimension. The extent of the first (and only) subsciipt of array
a ge is 20, and the extent of the first (and only) subscript of array 1 a s t_n ame is

shape of an array is defined as the combination of its rank and the extent of th
in each dimension. Thus, two arrays have the same shape if they have the sam
and the same extent in each dimension. Finally, the size of an array is the total n
of elements declared in that array. For simple rank 1 arrays, the size of the arra
same as the extent of its single subscript. Therefore, the size of array vol tage
and the size of array 1 ast_name is 50,
Array constants may also be defined. An array constant is an array
ing entirely of constants. It is defined by placing the constant values
special delimiters, called array constructors. The starting delimiter of a
95 array constaictor is (/, and the ending delimiter of an array constructo
For example, the expression shown below defines an array constant containin
integer elements;

6.2
USING ARRAY ELEMENTS IN FORTRAN STATEMENTS
This section contains some of the practical details involved in using arrays in Fortran
programs.

6.2.1 Array Elements Are Just Ordinary Variables


Each element of an array is a variable just like any other variable, and an array ele

ment may be used in any place where an ordinary variable of the same type may be
used. Array elements may be included in arithmetic and logical expressions, and the
results of an expression may be assigned to an array element. For example, assume
that arrays i ndex and temp are declared as:
INTEGER, DIMENSION(IO) :: index
REAL. DIMENSI0N(3) :: temp

Then the following Fortran statements are perfectly valid:


i ndex(1) = 5
= RFAI(index(1)) / 4.
tpmp(3)
'
WRITE (*,*)
index(l) = ', ndex(l)

Under certain circumstances, entire arrays or subsets of arrays can be used in


expressions and assignment statements. These circumstances will be explained in
Section 6.3 below.

6.2.2 Initialization of Array Elements


Just as with ordinary variables, the values in an array must be initialized before use. If
an array is not initialized, the contents of the array elements are undefined. In the fol
lowing Fortran statements, array j is an example of an uninitialized array.
INTEGER, DIHENSION(IO)
'
=
WRITE {*,*)
j(l)

::
',

j
j(l)

The array j has been declared by the type declaration statement, but no values have
been placed into it yet. Since the contents of an uninitialized array are unknown and
can vary from computer to computer, the elements of the array should never be used
until they are initialized to known values.

6.2.3 Changing the Subscript Range of an Array


The elements of an //-element array are normally addressed using the subscript
s 1, 2,

...

,N. Thus the elements of array a r r declared with the statement


REAL,

DIHENSI0N(5) :;

arr

would be addressed asarr(l),arr(2), arr(3), arr(4), and arr (5). In some


prob
er sub
100. If

lems, however, it is more convenient to address the array elements with oth
scripts. For example, the possible grades on an exam might range from 0 to
we wished to accumulate statistics on the number of people scoring any given

grade,
d from
student's

ers that
nge, we
, with

it would be convenient to have a 101-element array whose subscripts range


0 to 100 instead of 1 to 101. If the subscripts ranged from 0 to 100, each
exam grade could be used directly as an index into the array.
For such problems, Fortran provides a way to specify the range of numb
will be used to address the elements of an array. To specify the subscript ra
include the starting and ending subscript numbers in the declaration statement
the two numbers separated by a colon.