After you finish a program, someone will often ask a "What if?" question. The person asking the question usually wants to know whether the program would still work if some of the restrictions implied by the problem statement were removed. If the answer is "No," you may have to modify the program to make it work. Try to anticipate these questions in advance and make your programs as general as possible right from the start. Sometimes this can be as easy as changing a program constant to a problem input.
One question that comes to mind for the last problem is: What if we wanted to find the sum and average of a list of any numbers, not just the sum of the first N integers. Would the program still work? Clearly, the answer to this question is "No." However, it would not be too difficult to modify the program to solve this more general problem.
PROBLEM SPECIFICATION
Write a program that finds and displays the sum of a list of numbers.
ANALYSIS
To add any list of numbers, a new variable (CurrentValue
) would be
needed to store each value to be summed. The numbers must be provided as input
data. Because the numbers are not necessarily positive, we will make
CurrentValue
and Sum
type Integer
.
Data Requirements
Problem Inputs
number of items to be summed (NumValues : Natural
)
temporary storage for each data value to be summed (CurrentValue:
Integer
)
Problem Outputs:
sum of the NumValues
data values (Sum: Integer
)
DESIGN
Initial Algorithm
1. Prompt the user for the number (NumValues
) of values to be
summed.
2. Prompt the user for each data value and add it to the sum.
3. Display the sum.
This algorithm is very similar to the earlier one. Step 2 is modified slightly and is refined below.
Algorithm Refinements
Step 2 Refinement
2.1. Initialize Sum
to 0.
2.2. FOR
each data value LOOP
Read the data value into CurrentValue
and add
CurrentValue
to Sum
.
END LOOP;
In this refinement, the variable CurrentValue
is used to store
each number to be summed. After each number is read into
CurrentValue
, it is added to Sum
. If there are more
data items, the loop body is repeated and the next data item replaces the last
one in CurrentValue
. The number of data values to be summed is
read into NumValue
before the loop is reached.
NumValues
determines the number of loop repetitions that are
required. A loop counter is needed to count the data items as they are
processed and to ensure that all data are summed.
Program Variables
loop counter--the number of data items added so far (Count :
Positive
)
IMPLEMENTATION
The general program to find the sum of a list of data items is shown in Program 5.4. We leave the test plan and testing as an exercise.
Program 5.4
WITH Ada.Text_IO; WITH Ada.Integer_Text_IO; PROCEDURE Sum_Items IS ------------------------------------------------------------------------ --| Finds and displays the sum of a list of data items. --| Author: Michael B. Feldman, The George Washington University --| Last Modified: July 1995 ------------------------------------------------------------------------ NumValues : Natural; -- input - the number of items to be added CurrentValue : Integer; -- input - the next data item to be added Sum : Integer; -- output - the sum being accumulated BEGIN -- Sum_Items -- Read the number of items to be summed Ada.Text_IO.Put (Item => "Enter number of integer items to be summed > "); Ada.Integer_Text_IO.Get(Item => NumValues); Ada.Text_IO.New_Line; -- Read each data item and add it to Sum Sum := 0; FOR Count IN 1 .. NumValues LOOP Ada.Text_IO.Put(Item => "Integer item no. "); Ada.Integer_Text_IO.Put(Item => Count, Width => 1); Ada.Text_IO.Put(Item => " to be summed > "); Ada.Integer_Text_IO.Get(Item => CurrentValue); Sum := Sum + CurrentValue; END LOOP; -- Print the sum Ada.Text_IO.Put(Item => "The Sum is "); Ada.Integer_Text_IO.Put(Item => Sum, Width => 1); Ada.Text_IO.New_Line; END Sum_Items;Sample Run
Enter number of integer items to be summed > 6 Integer item no. 1 to be summed > 4 Integer item no. 2 to be summed > -7 Integer item no. 3 to be summed > 0 Integer item no. 4 to be summed > 24 Integer item no. 5 to be summed > -10 Integer item no. 6 to be summed > 1 The Sum is 12
We can further generalize this solution to find the minimum, maximum, and
average of a list of data values--for example, the results of a class
examination. The average is computed by finding the sum of all the values, then
dividing by the number of values. From the previous example, we know how to
find the sum. The minimum and maximum can be found at the same time, using our
package Min_Max
.
PROBLEM SPECIFICATION
Write a program that finds and displays the minimum, maximum, and average of a list of integers.
ANALYSIS
This is quite similar to the previous problem. We can use the variables
CurrentValue
and Sum
as above. As each value is read,
it must be added into the sum and also compared against the current minimum,
Smallest,
and the current maximum, Largest
. The
comparisons can be handled by the Minimum
and Maximum
functions already provided in the MinMax
package.
Because each new value, including the first, needs to be compared to
Smallest
and Largest
, what initial values should
these two variables have? It might be tempting to simply initialize them to
zero, like the sum. This would be a mistake: Suppose that all the values to be
read happened to be positive? The program would give incorrect results, since
it would report that the smallest value was zero, instead of the really
smallest value (which in this case would be greater than zero).
One way to solve this problem is to initialize Smallest
to the
largest possible integer value we will accept from the user. For now, we
will just let this be the largest possible value of the type
Integer
. This way, any value the user could enter would
automatically be no larger than this initial value. Luckily, Ada gives us an
easy way to discover the largest possible value of Integer
: It is
an attribute called Integer'Last
. (Notice the use of the
apostrophe in the syntax.) This value is a large number whose actual value
depends upon the compiler you are using. Because we also need to find the
largest number, we should initialize Largest
to the
smallest possible Integer
value, which Ada calls
Integer'First.
Data Requirements
Problem Inputs
number of items to be averaged (NumValues : Positive
)
temporary storage for each data value (CurrentValue: Integer
)
Problem Outputs
minimum of the NumValues
data values (Smallest:
Integer
)
largest of the NumValues
data values (Largest:
Integer
)
average of the NumValues
data values (Average:
Integer
)
Initial Algorithm
1. Prompt the user for the number (NumValues
) of values to be
summed.
2. Prompt the user for each data value; add it to the sum, check to see if it is a new minimum, and check to see if it is a new maximum.
3. Compute the average of the values.
4. Display the minimum, maximum, and average.
This algorithm is very similar to the earlier one. Step 2 is modified and is refined below; there is a new step 3.
Algorithm Refinements
Step 2 Refinement
2.1. Initialize Sum
to 0, Smallest
to
Integer'Last
, and Largest
to
Integer'First
.
2.2. FOR
each data value LOOP
Read the data value into CurrentValue
and add
CurrentValue
to Sum
;
determine whether the data value is a new minimum or maximum
END LOOP;
In this refinement, the variable CurrentValue
is used to store
each number to be summed. After each number is read into
CurrentValue
, it is added to Sum
. If there are more
data items, the loop body is repeated and the next data item replaces the last
one in CurrentValue
. The number of data values to be summed is
read into NumValues
before the loop is reached.
NumValues
determines the number of loop repetitions required. A
loop counter is needed to count the data items as they are processed and ensure
that all data are summed.
We need a further refinement of step 2.2:
Step 2.2 Refinement:
2.2 FOR
each data value LOOP
2.2.1 Read the data value into CurrentValue
and add
CurrentValue
to Sum
;
2.2.2 Replace Smallest
with the smaller of itself and
CurrentValue
;
2.2.3 Replace Largest
with the larger of itself and
CurrentValue
;
END LOOP;
Program Variables
loop counter--the number of data items added so far (Count :
Natural
)
IMPLEMENTATION
Program 5.5 shows the entire
program. Note that this program finds the average as an
integer value, by dividing Program 5.5 Sum
by NumValues
. This is
because all the numbers are integers and the division throws away the
fractional part of the quotient. In Chapter 7 we will
examine how to convert between integer and floating-point values.
WITH Ada.Text_IO; WITH Ada.Integer_Text_IO; WITH Min_Max; PROCEDURE Min_Max_Average IS ------------------------------------------------------------------------ --| Finds and displays the minimum, maximum, and average --| of a list of data items. --| Author: Michael B. Feldman, The George Washington University --| Last Modified: July 1995 ------------------------------------------------------------------------ NumValues: Positive; -- input - the number of items to be averaged CurrentValue: Integer; -- the next data item to be added Sum: Integer; -- program variable - the sum being accumulated Smallest: Integer; -- output - minimum of the data values Largest: Integer; -- output - maximum of the data values Average: Integer; -- output - average of the data values BEGIN -- Min_Max_Average -- Read the number of items to be averaged Ada.Text_IO.Put(Item => "Enter number (at least 1) of integer items to be averaged > "); Ada.Integer_Text_IO.Get(Item => NumValues); Ada.Text_IO.New_Line; -- Initialize program variables Smallest := Integer'Last; Largest := Integer'First; Sum := 0; -- Read each data item, add it to Sum, -- and check if it is a new minimum or maximum FOR Count IN 1 .. NumValues LOOP Ada.Text_IO.Put(Item => "Integer item no. "); Ada.Integer_Text_IO.Put(Item => Count, Width => 1); Ada.Text_IO.Put(Item => " > "); Ada.Integer_Text_IO.Get(Item => CurrentValue); Sum := Sum + CurrentValue; Smallest := Min_Max.Minimum(Value1 => Smallest, Value2 => CurrentValue); Largest := Min_Max.Maximum(Value1 => Largest, Value2 => CurrentValue); END LOOP; -- compute the average; since Sum and NumValues are integers, -- the average is truncated, that is, the fractional part is discarded Average := Sum / NumValues; -- Display the results Ada.Text_IO.Put(Item => "The Smallest is "); Ada.Integer_Text_IO.Put(Item => Smallest, Width => 1); Ada.Text_IO.New_Line; Ada.Text_IO.Put(Item => "The Largest is "); Ada.Integer_Text_IO.Put(Item => Largest, Width => 1); Ada.Text_IO.New_Line; Ada.Text_IO.Put(Item => "The Average is "); Ada.Integer_Text_IO.Put(Item => Average, Width => 1); Ada.Text_IO.New_Line; END Min_Max_Average;Sample Run
Enter number (at least 1) of integer items to be averaged > 7 Integer item no. 1 > -5 Integer item no. 2 > 2 Integer item no. 3 > 29 Integer item no. 4 > 16 Integer item no. 5 > 0 Integer item no. 6 > -17 Integer item no. 7 > 4 The Smallest is -17 The Largest is 29 The Average is 4
A modification of Program 5.5 could use an external (disk) file for the input data. In fact, most real-world computer programs make heavy use of external files. The user prepares a file of data using an editor, then uses it later as input to the program. If the program is being developed and debugged, requiring several test runs, preparing the data this way saves having to enter them interactively each time the program is tested. We shall cover this topic more systematically in Chapters 8 and 9; for now, let's just consider how Program 5.5 would be changed to allow an external file for input.
The Get
operations we have been working with all assume that
input is coming interactively from the keyboard. In fact, each Get
(for characters, strings, integers, floating-point quantities, and enumeration
literals) has a second form requiring an additional parameter that names a disk
file. For example, the input operation to read an integer value from a disk
file called, say, TestScores
, would be
Ada.Integer_Text_IO.Get(File => TestScores, Item => CurrentValue);
In general these operations look just like the interactive ones
except for the file name. TestScores
is an Ada variable, which
must be declared as
TestScores: Ada.Text_IO.File_Type;
The type File_Type
is provided by
Ada.Text_IO
.
Now suppose that the user prepared the input data with an editor and stored
them in a disk file called scores.dat
. The program needs a way to
associate the name of the file in the program (TestScores
in this
case) with the name of the file as it is known to the operating system
(scores.dat
in this case). This is done by means of an operation
called Ada.Text_IO.Open
. In this case the operation would look like
Ada.Text_IO.Open(File => TestScores, Mode => Ada.Text_IO.In_File, Name => "scores.dat");
The parameter Mode
indicates whether we are
reading from the file (Text_IO.In_File
, as in this example) or
writing to it (Text_IO.Out_File
). Notice also that the
operating-system file name must appear in quotes.
It is important to type the name of the file exactly as it is listed
in the directory you get from the operating system. Many operating systems use
case-sensitive file names, which means that if the operating system file
name is uppercase (e.g., SCORES.DAT
), your parameter in the
Open
statement must also be uppercase (as in our example); if the
operating system file name is in lowercase, your parameter must be also. If you
supply to Open
a file name that does not exist in your current
directory, the Ada exception Name_Error
will be raised.
Program
5.6 shows a modification of MinMaxAverage
in which input
values are read from a file instead of from the terminal keyboard. Notice that
there are no prompts, because there is no interactive user entering the data.
The file SCORES.DAT
, created with an editor, will contain first
the number of values to be read, then the actual values, one value per line.
The program "logs," or displays on the terminal, the values as they are read
from the file and processed; finally the results are displayed as before.
Program 5.6
WITH Ada.Text_IO; WITH Ada.Integer_Text_IO; WITH Min_Max; PROCEDURE Min_Max_Average_File IS ------------------------------------------------------------------------ --| Finds and displays the minimum, maximum, and average --| of a list of data items; the data items are read from a file. --| Author: Michael B. Feldman, The George Washington University --| Last Modified: July 1995 ------------------------------------------------------------------------ NumValues: Positive; -- input - the number of items to be averaged CurrentValue: Integer; -- input - the next data item to be added Smallest: Integer; -- output - minimum of the data values Largest: Integer; -- output - maximum of the data values Average: Integer; -- output - average of the data values Sum: Integer; -- program variable - the sum being accumulated TestScores: Ada.Text_IO.File_Type; -- program variable - names the input file BEGIN -- Min_Max_Average_File -- Open the file and associate it with the file variable name Ada.Text_IO.Open (File => TestScores, Mode => Ada.Text_IO.In_File, Name => "scores.dat"); -- Read from the file the number of items to be averaged Ada.Integer_Text_IO.Get(File => TestScores, Item => NumValues); Ada.Text_IO.Put("The number of scores to be averaged is "); Ada.Integer_Text_IO.Put(Item => NumValues, Width => 1); Ada.Text_IO.New_Line; -- Initialize program variables Smallest := Integer'Last; Largest := Integer'First; Sum := 0; -- Read each data item, log to the screen, add it to Sum, -- and check if it is a new minimum or maximum FOR Count IN 1 .. NumValues LOOP Ada.Integer_Text_IO.Get(File => TestScores, Item => CurrentValue); Ada.Text_IO.Put("Score number "); Ada.Integer_Text_IO.Put(Item => Count, Width => 1); Ada.Text_IO.Put(" is "); Ada.Integer_Text_IO.Put(Item => CurrentValue, Width => 1); Ada.Text_IO.New_Line; Sum := Sum + CurrentValue; Smallest := Min_Max.Minimum(Value1 => Smallest, Value2 => CurrentValue); Largest := Min_Max.Maximum(Value1 => Largest, Value2 => CurrentValue); END LOOP; -- compute the average; since Sum and NumValues are integers, -- the average is truncated, that is, the fractional part is discarded Average := Sum / NumValues; -- display the results Ada.Text_IO.Put(Item => "The Smallest is "); Ada.Integer_Text_IO.Put(Item => Smallest, Width => 1); Ada.Text_IO.New_Line; Ada.Text_IO.Put(Item => "The Largest is "); Ada.Integer_Text_IO.Put(Item => Largest, Width => 1); Ada.Text_IO.New_Line; Ada.Text_IO.Put(Item => "The Average is "); Ada.Integer_Text_IO.Put(Item => Average, Width => 1); Ada.Text_IO.New_Line; END Min_Max_Average_File;Sample Run
The number of scores to be averaged is 10 Score number 1 is 57 Score number 2 is 22 Score number 3 is 100 Score number 4 is 42 Score number 5 is 37 Score number 6 is 70 Score number 7 is 81 Score number 8 is 92 Score number 9 is 100 Score number 10 is 87 The Smallest is 22 The Largest is 100 The Average is 68
Copyright © 1996 by Addison-Wesley Publishing Company, Inc.