Chapter 4 - Loops
This chapter introduces the loop control model, which allows instructions to be repeated. This is
useful, for example, when we want to sum a number of rainfalls or customer purchases. Because
loops often have very specific forms, we identify these. Finally, the chapter covers file input and
output.
While Loop
The loop control model allows a number of instructions to be repeated. Typically, though, these
same instructions are done on different data. Of the various kinds of loops, the „while‟ is probably
the most flexible and is covered here.
The syntax of SAL‟s While instruction is:
Condition do
Instruction 1+
While
endWhile
This is the keyword While followed by the condition—a Boolean expression—followed by do
followed by one or more instructions followed by endWhile. The instructions inside the loop make
up the loop body.
The meaning of the While is shown in Figure 4.1. Prior to the instructions in the body being
done, the condition is tested. This condition is a Boolean expression. If the condition is true, then
the body is done and the condition tested again. If the condition is still true, the body is done a
second time. This cycle of testing the condition and doing the loop body continues while the
condition is true. At some point, the condition should become false. Now, the loop stops and the
instructions after the loop are done.
Instructions
before While
False
Condition
True
Body
Instructions
Instructions
after While
Figure 4.1 - While instruction flowchart
Loops
35
Algorithm 4.1 shows an algorithm for summing the total quarts of strawberries picked by
customers at a self-pick strawberry farm. The loop is done repeatedly while there is more input. This
allows summing the quarts or strawberries picked. After the loop, the total quarts are output. Figure
4.2 shows a sample run. In the next section, we‟ll see what the InputOk means as well as more
closely examining how loops work (including why there are two Inputs in Algorithm 4.1).
Algorithm 4.1 - Summing strawberries picked
% This algorithms sums the number of quarts picked at a strawberry farm.
Set totQuarts to 0
Output "Enter quarts picked: "
Input quarts
While InputOk do
Set totQuarts to totQuarts + quarts
Output "Enter quarts picked: "
Input quarts
endWhile
Output "Total quarts picked is ", totQuarts
Enter
Enter
Enter
Enter
Enter
Enter
Total
quarts
quarts
quarts
quarts
quarts
quarts
quarts
picked:
picked:
picked:
picked:
picked:
picked:
is 36
4
3
12
8
9
^D
Figure 4.2 – Strawberry picking sample run
It turns out that most loops fall into one of just a few forms. Recognizing different loop forms
goes a long ways toward solving a problem. The next section covers common loop forms as well as
more problem solving.
Loop Forms
The previous section introduced the While instruction, which is probably the most-used kind of loop
control. Loops expand significantly the kinds of problems we can solve, including processing a lot of
data. In all of these solutions, though, loops usually fall into one of just a few forms. In this section,
we look at common loop forms. These include the standard input loop as well as counting and
event-controlled loops.
A standard input loop is used to input data either interactively or from a file until there is no
more data. Sometimes this kind of loop is called an end-of-file (controlled) loop. Algorithm 4.1 had a
standard input loop. A standard input loop looks like:
Input first data
While InputOk do
…
Input next data
endWhile
36
Loops
There are two Input instructions, one immediately before the loop and one at the end of the loop
body. The condition in the While tests whether input is successful, i.e. data was input. InputOk is a
special symbol having the value true if the last input was successful and false if not.
The Input immediately before the While is called a priming input. By “priming,” it is meant
that the first data is input before InputOk is tested. The first input must be before this test because
InputOk reflects what happens in the last input. This is important. InputOk does not test whether
there is more data yet to be input but only if the last Input instruction was successful. An Input is
successful if data is input for each variable in the instruction.
There is also an Input instruction at the end of the loop body. This is where all data is input
except for that input by the primer. Also note the logical structure of the loop. Because the Input
instruction is at the end of the loop body, the very next thing that occurs is that InputOk is tested.
This is exactly what we want.
To indicate that there is no more data, the user types ^D. This is the two-key Ctrl-D (controlD) combination. If an Input instruction encounters a ^D in input, no data is input for a variable and
any future reference to InputOk will return false. This works only when ^D is pressed immediately
when input is needed. If anything else, including the space or the enter key, is pressed before ^D,
then the ^D has no effect. SAL has a built-in procedure called Clear that resets the keyboard input
stream, allowing more input from the keyboard. A built-in procedure is one that we call but we don‟t
write the procedure definition for. So, just by doing
Call Clear
the input stream is reset.
Let‟s look at a problem. Suppose we need an algorithm for calculating the average rainfall. The
input is the different rainfall amounts and the output, the average. Algorithm 4.2 shows a solution.
Algorithm 4.2 - Calculating the average rainfall
% This algorithm calculates an average rainfall.
Set totalRain to 0
Set count to 0
Output "Enter a rainfall amount: "
Input amount
While InputOk do
Set totalRain to totalRain + amount
Set count to count + 1
Output "Enter another amount: "
Input amount
endWhile
Set avgRain to totalRain / count
Output "The average rainfall is ", avgRain
Algorithm 4.2 contains a standard input loop. The first rainfall is input before the loop.
Provided there is a first rainfall, the input would be successful. Inside the loop, this rainfall amount is
added to the total, and the count of rainfalls incremented by one. Then, the next amount is prompted
for and input. Because the input is at the end of the loop, the next thing that happens is the
condition is tested again. This is what we want. Figure 4.3 shows a sample run.
Loops
37
Enter a rainfall amount: 0.8
Enter another amount: 0
Enter another amount: 0
Enter another amount: 1.1
Enter another amount: ^D
The average rainfall is 0.4750
Figure 4.3 - Average rainfall sample run
Let‟s trace this algorithm for the data used in Figure 4.3. A trace tracks the values of variables
in an algorithm and any user interaction. Here‟s the trace:
totalRain
count
0
0.8
0.8
0
0.8
1.9
1
2
3
4
amount
avgRain
Interaction
0.475
Enter a rainfall amount: 0.8
Enter another amount: 0
Enter another amount: 0
Enter another amount: 1.1
Enter another amount: ^D
The average rainfall is 0.4750
0.8
0
0
1.1
User input is bold. A trace allows us to track what a computer does when running an algorithm. The
first line in the trace shows that totalRain and count are set to 0. In the second line, we see that
totalRain is 0.8, count 1, and amount 0.8. This is because the first rainfall has been input and
added to the total. The interaction part shows the prompts and user input and results. Later lines in
the trace show changes to variables as more input is read.
The order the variables are written in a trace is not important. Often, the author writes them in
the order they first occur in an algorithm. Sometimes, though, this might result in variables not
necessarily related being written side-by-side. In any case, what is important is the values that
variables have. These must be recorded accurately for the trace to be useful. We‟ll do more traces as
we go along.
The above example hints at a common mistake that is often made: to forget to initialize a total.
Some languages will initialize a variable to a default value, usually 0. To avoid mistakes of this sort,
we need to get into the habit of initializing variables. Be careful, though, not to initialize a variable if
it isn‟t needed. While such initialization will not result in an incorrect algorithm, it can be confusing
when reading an algorithm and wondering what an initialization is for.
Algorithm 4.2 shows another example where literals should not necessarily be replaced with
constants. Initializing a count to 0 or 1 and totals to 0 should probably just be done using literals.
Otherwise, we end up doing things like
Constant ^INIT_VALUE 0
and later:
Set total to ^INIT_VALUE
This might not be easier to read and just makes an algorithm longer. When to use a constant and
when not to will come with practice. For now, if it‟s plain which it should be, then make the obvious
choice. If it‟s uncertain, then using a constant is the thing to do.
Let‟s revise the sales commission problem from the previous chapter. This time, though, we
want to calculate the commissions for several salespeople. Algorithm 4.3 shows a solution. And,
Figure 4.4 shows a sample run.
38
Loops
Algorithm 4.3 - Calculating sales commissions
% This algorithm calculates the sales commissions for several people. The
% commission is a percentage of the selling price plus a possible bonus.
Constant ^MIN_FOR_BONUS 145000
Constant ^BASE_COMM 0.05
Constant ^BONUS 1000
Output "Enter salesperson's name and price of house: "
Input name, price
While InputOk do
Set commission to price * ^BASE_COMM
If price >= ^MIN_FOR_BONUS
then Set commission to commission + ^BONUS
endIf
Output "The commission for ", name, "is ", commission:2
Output newline, "Enter salesperson's name and price of house: "
Input name, price
endWhile
Enter salesperson's name and price of house:
The commission for Mark is 4750.00
Enter salesperson's name and price of house:
The commission for Wei Min is 11750.00
Enter salesperson's name and price of house:
The commission for Cheryl is 3949.50
Enter salesperson's name and price of house:
Mark 95000
"Wei Min" 215000
Cheryl 78990
^D
Figure 4.4 - Sample run for calculating sales commissions
Now, let‟s look at another loop form: the counting loop. A counting loop has the following
structure.
Initialize counter
While test counter do
…
Change counter
…
endWhile
The counter is used to cause a specific number of iterations of the loop.
Suppose we want to calculate 28. This problem is not as general as it could be, but it‟s a start.
Algorithm 4.4 shows a solution. The counter in this algorithm is count. It is initialized to zero and
incremented in each iteration of the loop. The condition tests that the counter is less than 8. Because
the counter is initialized to zero, count will be 0, 1, 2, 3, 4, 5, 6, and 7 in successive iterations. In the
last iteration, count is incremented to 8. This will stop the loop.
Loops
39
Algorithm 4.4 - 2-to-the-8th power
% This algorithm calculates 2 to the 8th power.
Output "Calculate 2-power-8 Algorithm"
Set count to 0
Set answer to 1
While count < 8 do
Set answer to answer * 2
Set count to count + 1
endWhile
Output newline, "The answer is ", answer
Here‟s the trace for Algorithm 4.4:
count
answer
Interaction
0
1
2
3
4
5
6
7
8
1
2
4
8
16
32
64
128
256
Calculate 2-power-8 Algorithm
The answer is 256
In Algorithm 4.4, the counter starts at zero. Sometimes this is necessary. Other times, as in
Algorithm 4.4, the counter can start at 1. In this case, the While condition must test that the counter
is less than or equal to 8. In successive iterations of the loop, count will be 1, 2, 3, 4, 5, 6, 7, and 8.
Algorithm 4.5 - 2-to-the-8th power (solution 2)
% This algorithm calculates 2 to the 8th power.
Output "Calculate 2-power-8 Algorithm"
Set count to 1
Set answer to 1
While count <= 8 do
Set answer to answer * 2
Set count to count + 1
endWhile
Output newline, "The answer is ", answer
Let‟s change the power problem to calculate any non-negative power of two. Algorithm 4.6
shows a solution. Note that n is input prior to the loop. In this way, when the loop is started, n will
have a value.
Algorithm 4.6 - 2-to-the-nth power continued on next page
% This algorithm calculates 2 to the nth power for an input n.
Output "Calculate 2-power-n Algorithm"
Output "Enter n (integer, >= 0): "
Input n
Set count to 0
Set answer to 1
While count < n do
Set answer to answer * 2
40
Loops
Set count to count + 1
endWhile
Output "The answer is ", answer
Let‟s look at another problem. An algorithm is needed to add up the scores of rounds of a
game for a single player. Algorithm 4.7 shows a solution. Figure 4.5 shows a sample run. Note that a
counting loop can also have input. Just like a standard input loop can have a counter in it, so can a
counting loop have input. It is the condition being tested in the While that determines what loop
form it is. Finally, note that a user does not enter ^D in the input for Algorithm 4.7. Instead, the
counting loop ensures that only as many prompts as needed are actually output.
Algorithm 4.7- Summing game rounds
% This algorithm totals the scores of rounds of a game.
Constant ^NUM_ROUNDS 6
Set total to 0
Set round to 0
While round < ^NUM_ROUNDS do
Set round to round + 1
Output "Enter score on round ", round, ": "
Input score
Set total to total + score
endWhile
Output "The total score is ", total
Enter score on round 1:
Enter score on round 2:
Enter score on round 3:
Enter score on round 4:
Enter score on round 5:
Enter score on round 6:
The total score is 678
119
87
134
129
97
112
Figure 4.5 - Game rounds sample run
Algorithm 4.8 shows a solution to a slight variation of the game problem. This time, scores are
prompted for until the user indicates no more input. This requires use of a standard input loop and
not a counting loop. A sample run for the same data as in Figure 4.5 is shown in Figure 4.6.
Algorithm 4.8 - Summing an unknown number of game rounds
% This algorithm totals the scores of rounds of a game
Set total to 0
Set round to 1
Output "Enter score on round ", round, ": "
Input score
While InputOk do
Set total to total + score
Set round to round + 1
Output "Enter score on round ", round, ": "
Input score
endWhile
Output newline, "The total score is ", total
Loops
41
Enter score on round 1:
Enter score on round 2:
Enter score on round 3:
Enter score on round 4:
Enter score on round 5:
Enter score on round 6:
Enter score on round 7:
The total score is 678
119
87
134
129
97
112
^D
Figure 4.6 - Another games round sample run
Suppose we need to calculate the total return for a one-year savings certificate for a range of
annual percentage yields. This range is input. Algorithm 4.9 shows a solution.
Algorithm 4.9 - Calculating returns on a savings certificate
% This algorithm outputs the return of a $5,000 one-year
% savings certificate for a range of interest yields. This range is input.
Constant ^AMOUNT 5000
Constant ^INCR_YIELD 0.5
Output "Enter lowest annual percent yield: "
Input lowYield
Output "Enter highest annual percent yield: "
Input highYield
Set yield to lowYield
While yield <= highYield do
Set interest to ^AMOUNT * yield / 100
Set totReturn to ^AMOUNT + interest
Output newline, "At APY ", yield:2, "%, the total return is ",
totReturn:2
Set yield to yield + ^INCR_YIELD
endWhile
If yield != highYield
then Set interest to ^AMOUNT * highYield / 100
Set totReturn to ^AMOUNT + interest
Output newline, "At APY ", APYperc:2, "%, the total return is ",
totReturn:2
endIf
Algorithm 4.9 contains a counting loop. This loop, though, doesn‟t start at 0 or 1 but at
whatever value is input by the user. The limit of the counter, here yield, is also input. Note that
yield is incremented by 0.5. This makes for a loop that counts by something different than 1. This is
fine—we can count by any change that we require. The two yields are input looking like percentages.
For example, an input 4 means 4%. As a real number, this is actually 0.04. This is why the interest
calculations include division by 100.
Finally, look at the selection after the loop. This is to output the total return at the high yield if
it is not done so in the loop. The return for the high yield only happens inside the loop if the counter
reaches exactly the high yield. Figure 4.7 shows a sample run. Note that the next-to-last line was
output in the last iteration of the loop and the last line in the If.
42
Loops
Enter lowest annual percent yield: 4.3
Enter highest annual percent yield: 7.1
At
At
At
At
At
At
At
APY
APY
APY
APY
APY
APY
APY
4.30%,
4.80%,
5.30%,
5.80%,
6.30%,
6.80%,
7.10%,
the
the
the
the
the
the
the
total
total
total
total
total
total
total
return
return
return
return
return
return
return
is
is
is
is
is
is
is
5215.00
5240.00
5265.00
5290.00
5315.00
5340.00
5355.00
Figure 4.7 - Savings certificate sample run
Here‟s one more counting-loop problem. This time, we‟ll count backwards. An algorithm is
needed to output the equivalent Celsius degrees for Fahrenheit ones from the boiling point to
freezing. This requires counting backwards from boiling to the freezing point. We‟ll do this 10
degrees at a time.
Algorithm 4.10 - Fahrenheit to Celsius converter
% The equivalent in Celsius for Fahrenheit degrees are computed from
% the boiling point to freezing.
Constant ^F_START 212
Constant ^F_END 32
Constant ^F_STEP 10
Set fDegs to ^F_START
While fDegs >= ^F_END do
Set cDegs to (fDegs – 32) * 5 / 9
Output newline, fDegs, " Fahrenheit equals ", cDegs, " Celsius"
Set fDegs to fDegs – ^F_STEP
endWhile
Standard input loops and counting loops have specific forms. There is another kind of loop
that is a more general: the event-controlled loop. Here, the continuation of a loop depends on some
event. Both input and counting loops can be viewed as special kinds of event-controlled loops. In the
former, successful input continues the loop. In a counting loop, comparison of the counter is the
event tested for. There are other loops, though, that don‟t fall so neatly into either of these two
formats.
The format of an event-controlled loop is simple enough:
Initialize the event
While event do
…
Affect the event
…
endWhile
While the event, specified in the condition, is true, the loop continues. As with other loops,
something must occur either prior to the loop or in the loop body to make the event false. Let‟s look
at some problems.
Suppose we want to calculate how many years it takes for inflation to double at some inflation
rate. This will require compounding inflation from one year to the next until inflation doubles. There
Loops
43
will be a loop that compounds the inflation. The event is when inflation doubles. Algorithm 4.11
shows a solution.
Algorithm 4.11 - Doubling inflation
% This algorithm calculates how many years is needed for inflation to
% double at a specific inflation rate.
Output "Enter the inflation rate (for example, 0.04 is 4%): "
Input rate
Set value to 1
Set years to 0
While value < 2 do
Set value to value * (1 + rate)
Set years to years + 1
endWhile
Set decRate to rate * 100
Output "At ", decRate, "%, it takes ", years,
" years for inflation to double. "
As with other problems, there can be a number of different solutions. The solution presented
here starts with a value of 1 and then compounds the inflation until this value reaches 2, doubling the
initial value. Note that the loop counts how many years it takes to double inflation. This counting,
though, does not control the loop. Instead, the event is while the value is less than 2, continue
compounding.
Now, suppose we want an algorithm for a simple guessing game. The user is to be continually
prompted to guess a digit between 0 and 9 until the correct guess is made. The event, here, is while
the guess is not correct, continue guessing. Algorithm 4.12 shows a solution.
Algorithm 4.12 - A simple guessing game
% This is a simple guessing game. The user is prompted for guesses
% until the answer is guessed.
Constant ^GUESS_NUM 8
Output "Guess a digit between 0 and 9: "
Input guess
While guess != ^GUESS_NUM do
Output "No, sorry."
Output newline, "Guess again: "
Input guess
endWhile
Output "You got it!"
Looking at the guessing game, it almost looks like we have a standard input loop. There is the
primer input and the input at the bottom of the loop. The condition in the While, though, is not that
for an input loop. Instead, the condition tests the event that a guess is not correct.
Let‟s modify the simple guessing game. This time, we will allow a user to quit the game at any
time if not able to guess correctly. The loop, then, needs to allow guessing to continue while input is
successful and the digit is not guessed. Algorithm 4.13 solves this problem.
44
Loops
Algorithm 4.13 - Use of a flag
% This is a simple guessing game. The user is prompted for guesses
% until the answer is guessed.
Constant ^GUESS_NUM 8
Set guessing to true
Output "Guess a digit between 0 and 9"
While guessing do
Input guess
If InputOk
then If guess == ^GUESS_NUM
then Output "You got it!"
Set guessing to false
else Output "No, sorry."
Output newline, "Guess again: "
endIf
else Set guessing to false
endIf
endWhile
The condition tests for the event. In this case, it is a single variable (sometimes referred to as a
flag) to test whether guessing should continue. In the body of the loop, we first check to make sure
that the input was successful. If it is, them the correct guess is checked for. If the guess is correct,
then the appropriate message is output and guessing is set to false. This will stop the loop from
being done again. Otherwise, if the guess was incorrect, the user is prompted for another guess. Note
that there is only one Input in Algorithm 4.13 and two prompts! On close examination, though,
logically both prompts are immediately followed by the Input. So, this will work.
The remainder of this section looks at some more difficult problems. And, we‟ll point out
some tips as we go along. We‟ll also see nesting one loop inside another.
Algorithm 4.14 shows a solution for computing the Fibonacci Series. The Fibonacci Series is 0,
1, 1, 2, 3, 5, 8, 13, 21, 34, and so on. The first two entries in the Series are 0 and 1. Every entry
thereafter is the sum of the previous two. For example, 13 is the sum of 5 and 8. The algorithm
generates all of the entries in the Fibonacci Series up to a limit that is input by the user. Oh, the
Fibonacci Series is often found in nature. For example, the series models the number of petals found
on many flowers.
Algorithm 4.14 - Computing the Fibonacci Series
% This algorithms creates the Fibonacci Series 0, 1, 1, 2, 3, 5, 8,
% 13, etc., to some input limit. Note that but for the first two, all
% numbers in the series are the sum of the previous two.
Output "The Fibonacci Series"
Output newline, "Enter the series limit: "
Input limit
Set first to 0 % First number in series
Output first
Set second to 1 % Second number in series
Output newline, second
Set next to first + second % The third number
While next <= limit do
Output newline, next
Set first to second % Adjust to new previous
Set second to next
%
two numbers
Set next to first + second % Next number in the series
endWhile
Loops
45
To solve the Fibonacci problem, we need to keep track of the previous two numbers. At the
start, the first two numbers are 0 and 1. So, we remember these in variables (in first and second).
From there, the next number is the sum of these two. After this, in preparation for calculating the
next number, we remember the second number in the first variable and the number just computed in
the second variable. If we sum the first and second again, we get the fourth number in the Series.
This saving of the second and next numbers can be repeated to continue getting more numbers in
the series.
Here‟s the trace for input 50:
limit
first
second
0
1
1
1
2
3
5
8
13
21
1
2
3
5
8
13
21
34
next
50
1
2
3
5
8
13
21
34
55
Interaction
The Fibonacci Series
Enter the Series limit: 50
0
1
1
2
3
5
8
13
21
34
It might look as if some values are left out early in the trace. This is not the case. The trace is just
drawn to keep changes in variables and affected interaction on the same lines if possible. This can
help organize a trace and make it more meaningful. Note that next goes to 55 but is not output. This
is because it is calculated at the end of the While but the Output instruction is at the start of the loop
body. The condition in the While will be false after next becomes 55, preventing the loop from
being done again.
The Fibonacci solution has an event-controlled loop. Also, note that the solution shows a
technique that occurs on occasion. This is to track a pair of successive values from one pass of the
loop to the next. This was done by setting first to second and then second to next. The order of
these assignments is important.
Now, let‟s take the insurance problem from the previous chapter. The problem is to calculate
the yearly cost for insuring auto customers. Customers who have been accident-free for a minimum
number of years get the safe-driver premium. Everyone else pays the full cost. In addition, anyone
paying the full cost can qualify for a deduction if an examination has been passed. Now, we want to
modify the algorithm to process several customers and output the total premiums. Algorithm 4.15 is
a solution.
Algorithm 4.15 - Insuring multiple customers continued on next page
% This algorithm computes the cost of insuring an auto customer. This
% cost is based on whether a customer is accident-free for a minimum number
% of years. Also, taking a driver examination will discount a full cost.
Constant
Constant
Constant
Constant
^FULL_COST 1200
^SAFE_COST 850
^EXAM_DEDUCT 100
^MIN_FREE 3
Set totPremiums to 0
Output newline, "New customer -- Years accident free: "
Input years
46
Loops
While InputOk do
If years < ^MIN_FREE
then Set premium to ^FULL_COST % Pay full cost
Output "Driving exam since last accident? "
Input exam
Call Lower(exam, examLow)
If examLow == "y" % Check for a driver examination
then Set premium to premium – ^EXAM_DEDUCT
endIf
else Set premium to ^SAFE_COST % Safe-driver premium
endIf
Output "Premium cost is ", premium:2
Set totPremiums to totPremiums + premium
Output newline, "New customer -- Years accident free: "
Input years
endWhile
Output newline, "The total premiums is ", totPremiums:2
Besides the need for totPremium, Algorithm 4.15 is exactly the insurance algorithm from the
previous chapter except that it includes a standard input loop for processing multiple customers.
Many times, it is easier to develop a solution for processing just a single customer or whatever data is
being used, and the incorporating that solution into a loop.
Loops can be nested, writing one loop entirely within another. (Recall nesting in general: any
control model can be nested in any other.) Suppose an elementary school needs an algorithm to assist
students with learning multiplication tables. One multiplication table shows the products for an input
multiplicand multiplied by 0 through 9. For example, the 8‟s multiplication table looks like:
8 times 0 equals 0
8 times 1 equals 8
8 times 2 equals 16
8 times 3 equals 24
8 times 4 equals 32
8 times 5 equals 40
8 times 6 equals 48
8 times 7 equals 56
8 times 8 equals 64
8 times 9 equals 72
Algorithm 4.16 shows a solution.
Algorithm 4.16 - A simple computer-aided instruction program
% This algorithm creates multiplication tables for input multiplicands.
Output "Multiplication Tables"
Output newline, "Enter a multiplicand: "
Input multiplicand
While InputOk do
Set k to 0
While k <= 9 do % One multiplication table
Set product to multiplicand * k
Output newline, multiplicand, " times ", k, " equals ",
product
Set k to k + 1
endWhile
Output newline, newline, "Enter another multiplicand: "
Input multiplicand
endWhile
Loops
47
Algorithm 4.16 contains a loop nested inside another. The outer loop is an input loop that
allows more than one multiplication table to be generated. The inner loop makes the actual table. It is
a counting loop that counts from 0 to 9. These are the multipliers.
File Input and Output
In addition to interactive input and output, data can be input from a file and results output to a file.
The use of loops makes processing large amounts of data straightforward. This data can be saved in a
file and input instead of being input interactively. This can be convenient for a user if data is
collected as a separate activity or if there is the potential for the same data to be used more than
once. File output provides a ready means of saving results.
Here‟s an example file of rainfall amounts:
0.1
0
0.2
0.1
0
0
0.4
1.3
0
0.3
In addition, a file has a name. For the rainfalls example, this might be „june2004.data‟. Because there
can be a number of files, we want to be able to distinguish among them with different filenames.
Recall the syntax of the Input and Output instructions:
Input
[ @keybd | @FileHandle ] Variable < , Variable > 0+
Output
[ @screen | @FileHandle ] Argument < , Argument > 0+
The file handle is used to indicate whether input is from a file or output is to a file.
To associate a file handle with an actual file, we use the Open instruction: Here‟s the syntax:
Open
{ in | out } FileName , FileHandle
The Open must be followed by either in or out. (The | and {, } together mean to choose one
option.) As guessed, in indicates that a file is to be opened for input, and out indicates an output
file. The rest of the instruction consists of the name of the file, comma, and a file handle. The
filename is a string having the name of the actual file to be opened. The file handle ties later Input or
Output instructions to the particular file.
Let‟s look at an example. Recall the average rainfall problem (for which Algorithm 4.2 was a
solution). This time, though, suppose the rainfall amounts are recorded in a file. Algorithm 4.17
shows a solution to calculate the average rainfall where the amounts are input from a file.
Algorithm 4.17 - Calculating the average rainfall from file input
% This algorithm calculates an average rainfall from amounts recorded in
% a file.
48
Loops
Output "Enter rainfall file name: "
Input filename
Open in filename, rainFile
Set totalRain to 0
Set count to 0
Input @rainFile amount
While InputOk(rainFile) do
Set totalRain to totalRain + amount
Set count to count + 1
Input @rainFile amount
endWhile
Set avgRain to totalRain / count
Output "The average rainfall is ", avgRain
The filename is prompted for and then input. At this point, the file must be opened. The Open
causes the file handle rainFile to be associated with the actual file. The name of this file is the value
of filename. After the Open, data is then input as with interactive input except for three
differences. First, because the input is from a file, there is no need for a prompt. Second, the Input
instruction must have the file handle, indicating where the input is from. Finally, we must use
InputOk(rainFile) instead of just InputOk.
Here‟s a trace for Algorithm 4.17 using the sample rainfall file from the beginning of this
section:
filename
rainfile
totRain
count
amount
june2004.data
File handle
0
0.1
0.1
0.3
0.4
0.4
0.4
0.8
2.1
2.1
2.4
0
1
2
3
4
5
6
7
8
9
10
0.1
0
0.2
0.1
0
0
0.4
1.3
0
0.3
avgRain
2.4
Interaction
Enter rainfall file name: june2004.dat
The average rainfall is 2.4000
File Handle under rainfile just means the file handle, which is represented inside the computer
using a data type we do not need to know.
Here‟s another problem. A store needs an algorithm to calculate new prices from existing ones.
The store‟s inventory is recorded in a file. Each entry is the name of an item followed by its price.
The algorithm is to input each item, calculate its new price, and output the item name and new price
to a file. Algorithm 4.18 shows a solution.
Algorithm 4.18 - Determining new prices continued on next page
%
%
%
%
This algorithm computes the new prices for items in a store
where everything is changed by the same percentage. Input is from a
file consisting of item names and prices. Output is the items and new
prices. These are output to a file.
Loops
49
Constant ^CHANGE -0.15
% For a 15% decrease
Output "Enter input inventory file name: "
Input filename
Open in filename, inFile
Output "Enter output file name: "
Input filename
Open out filename, outFile
Input @inFile item, price
While InputOk(inFile) do
Set newPrice to price * (1 + ^CHANGE)
Output @outFile newline, item, " ", newPrice
Input @inFile item, price
endWhile
Both input and output are with files. At the start of the algorithm, both filenames are prompted
for and the files opened. These filenames must be different. From here, a standard input loop is used
to input each item in turn, calculate its new price, and is then written to the output file. Note that
filename is used to input both the input and output file names. This is fine because the input
filename is no longer needed after that file has been opened. Therefore, the same variable can be
used again.
Unlike in some languages, files in SAL do not have to be closed. If the same file is opened a
second time for input, input starts anew at the beginning of the file. Whenever a file is opened for
output, that file is initially made empty. Therefore, opening an existing file for output will cause any
data in the file to be lost.
Let‟s echo the above inventory file (either with the old or new prices). This just requires
reading data from the input file, and writing it to the output—in this case, the screen. This is what‟s
meant by “echoing” a file. Algorithm 4.19 shows a solution.
Algorithm 4.19 - Echoing an inventory file
% This algorithm echoes a file of item names and prices.
Output "Enter inventory file name: "
Input inventName
Open in inventName, inFile
Input @inFile item, price
While InputOk(inFile) do
Output newline, item, " ", price
Input @inFile item, price
endWhile
Here‟s one more problem. A competition needs a scoring algorithm. How it works is that
seven judges enter a score. These are saved in a file. The scores need to be input and their average
calculated, not counting the highest and lowest scores. In this way, the average is of the five middle
scores. Algorithm 4.20 shows a solution.
Algorithm 4.20 - Scoring an event continued on next page
% This algorithm computes the average score, dropping the highest and
% lowest scores.
Constant ^NUM_JUDGES 7
Output "Enter the scores file name: "
Input filename
Open in filename, scoreFile
50
Loops
Input @scoreFile score
Set largest to score % The first score is the largest so far
Set smallest to score % The same for the smallest
Set total to score
Set count to 1
While count < ^NUM_JUDGES do
Input @scoreFile score
Set total to total + score
If score > largest % New largest score?
then Set largest to score
else If score < smallest % Else, new smallest score?
then set smallest to score
endIf
endIf
Set count to count + 1
endWhile
Set total to total – largest – smallest
Set mean to total / (NUM_JUDGES – 2)
Output "The mean judges score is ", mean
The algorithm works by totaling all the scores and then subtracting out the largest and smallest
before calculating the average. The largest and smallest scores are initialized to the very first score
input. This is fine in that if any later score is larger or smaller, it will be remembered. A counting loop
is used to input the remaining scores. Each score is compared to the largest one so far. If the input
score is larger, then it is remembered as the new largest. On the other hand, the score is compared to
the smallest one and remembered if it is a new smallest score.
This concludes our look at file I/O. The key thing about file I/O is to remember that files
must be opened before they are used. Furthermore, Input and Output instructions must include file
handles. And, finally, the input file handle is used with the InputOk function.
In summary, this chapter introduced loop control and file I/O. Loop control—we looked at the
While specifically—increase significantly the kinds of problems we can solve. This includes handling
large amounts of data. File I/O, then, naturally followed as a way of recording such large data sets.
Key Terms
File input and output
Loop control model
Loop types
Counting loop
Event-controlled loop
Standard input loop
Open instruction
While instruction
Loops
51
52
Loops
© Copyright 2026 Paperzz