Previous Section Main Menu Next Section

CHAPTER THREE

Analysis and Design : First Steps

Section IV: The While Loop With Priming Read Pattern Section I : Problem Analysis Section II: Problem Analysis Section III: Patterns Section V: The Counter Pattern
Section VI: The Sum Pattern Section VII: The Average Pattern Section VIII: The Salary Problem Revisited Section IX: Taking Advantage of Patterns

The "While Loop with Priming Read" Pattern
We will start first with one of the 'while' loop patterns. Suppose you are a sales clerk in a store. The store wants to have a "Friday the 13th Sale" where the prices of "selected" items are reduced by 13%. You have the job of figuring out the new prices. You know that the new price equals the old price times .87 (1.00 - .13) but this is ugly math and you want to automate the process. How about writing a program that allows you to enter each price after which the computer displays the new price.

If you think about it for a moment you realize that the program will include some kind of a loop - to allow it to repeatedly calculate the new price. But, how will the computer know when to stop looping? You could count the number of selected items to be discounted and have the computer loop that many times but there are two problems with this. First, if a large number of items have been selected, it could take awhile to do all the counting and your goal is to save time not take more time. Second, what if the manager adds or deletes items from the sale after you have made your count but before you are finished writing and running your program. You do not want to have to rewrite your program.

Usually in situations like this, the algorithm is designed so that the user (in this case, you will be both the programmer and the user of the program) has some way to signal to the computer when he or she is finished entering data. How about deciding that the user will enter a -1 (since no item costs less than 0 dollars) to indicate that there are no more items to discount.

Values that indicate that some loop should terminate are called sentinel values. In this case '-1' is a sentinel value. Sentinel values such as -1 can also be viewed as stopping conditions since they represent the conditions under which the loop should stop. Loops that involve such sentinel values or stopping conditions are very common and we can generalize the purpose of such a loop as follows:

So, how do we put together an algorithm to accomplish such a purpose? One might be tempted to write the following algorithm:

Let's test this algorithm with a trace. We will simplify the test by using only two, easy to work with, initial prices:

$10 and $100.

The user will enter these values one at a time and end with a -1 to indicate that there are no more prices to discount.

Remember how we do a trace. Step 1 is to make a column for each variable and put in 'garbage' (a question mark( - or the variable's initial value if it has been initialized. Our trace for this algorithm then starts as follows:

Price Discounted Price
? ?

Step 2 is to walk through the algorithm executing each instruction, being careful to do only what the algorithm says - no more, no less. In other words, don't do what you want to be done but what the instructions say is to be done.

The first instruction of our loop asks us (as the computer) to compare the value in 'Price' with -1. When we retrieve the contents of 'Price', we find that it holds garbage. OOPS! This means that 'Price' could have ANY value including -1. If it accidentally had a -1 as its value, the loop would stop before we had a chance to enter any values. Clearly, we have a problem! As a matter of fact, any time an algorithm attempts to use the value of a variable holding garbage there is a problem!

But let's assume that we don't have a problem here and see if everything else is OK. The first time through the loop the user enters $10 and the Discounted Price is $8.70 so our trace looks as follows:

Price Discounted Price
? ?
10 8.70

Output:   $8.70

Looks good so far. The computer returns to the top of the loop to run again the test that decides if the loop is finished. This time 'Price' has the value 10, which is not equal to -1, so the instructions inside the loop are executed again. The user enters $100, the Discounted Price is calculated and the trace becomes:

Price Discounted Price
? ?
10 8.70
100 87.00

Output:   $8.70    $87.00

Again, all is OK and again the computer returns to the top of the loop and compares 'Price' with -1. 100 does not equal -1 so the loop is entered again and this time the user enters -1. This means the loop should stop but note that the next instruction after

Get Price

has nothing to do with deciding if the loop should be discontinued. Yes, you and I know that the loop should stop but the computer doesn't. (Remember the warning to do what the instructions say when tracing, NOT what we want to have done.) So, the computer calculates the discount for a price of -1 dollars and even outputs that price. The trace contains:

Price Discounted Price
? ?
10 8.70
100 87.00
-1 -.87

Output:   $8.70    $87.00    $-.87

It's not so bad that the computer calculated the bogus discounted price but when it outputs a price of $-0.87, our program looks silly. Of course, the user can be told to ignore the final output and things will be OK but the program won't really be right and it certainly won't get much respect.

We have discovered that our algorithm has two problems. First, the first time through the loop the memory location symbolized by the variable 'Price' just might contain the value -1 in which case our program will terminate before it even gets started; and second, the final output will always be the strange $-0.87. Our algorithm needs to be fixed.

The problems actually are related. The cause of the first problem is that there is no input before the test condition in the while loop. The cause of the second problem is that the test condition is not executed right after the input is entered. It is this failure to test the value of the input immediately after it is entered that allows the system to calculate and output a discounted price for a 'price' of -1. Perhaps we need to rearrange the order of the input and test condition. The first thing we could do is move the input so that it takes place before the loop - to guarantee that 'Price' has a value before it is tested. Such a 'read instruction' is called a priming read. Here is the code:

Now, we are assured that there is something valid in 'Price' before we execute the while loop test condition. However, do you see the problem? If not, try running a trace on this - what happens?

**************************************

Hopefully, you have discovered that we have an infinite loop - the contents of the memory location symbolized by the variable 'Price' will never change so the 'Price' will never equal -1 (unless that was the first value entered) and the loop will never stop! OOPS!!!

Now, we could copy 'Get Price' back where it was and have the code:

Again, there is a problem. Take a moment to look at it and if you do not see it, try tracing the algorithm. If you still don't see the problem, compare your trace with one done for you

Now you realize that the problem is that the first price will not be discounted since it is read before the loop and another 'Get Price' is executed before the line:

Discounted Price = Price * Discount

is executed. So, what do we do? We can't remove the priming read line "Get Price' before the 'while' loop begins or we are back to problem number one and there must be a 'Get Price inside the 'while' loop or we have an infinite loop. The answer to this quandary lies in noting two things:

  1. We want the discount price calculation to take place before the second price is read in

  2. 'Get Price' should be executed just before the 'while' loop test condition is executed. (Remember that the reason the value -1 is being treated as a price is that the test condition is not executed right after the input.)

Putting these two facts together provides a hint as to where 'Get Price' should be inside the 'while' loop - at the bottom of the loop!

You may resist this idea but if you trace it, it does work. This approach works for all problems where the user enters a sentinel value to indicate the end of input. We therefore have our first pattern - expressed as a very general algorithm.

Pattern Name: The While Loop with Priming Read
Purpose: To loop through a set of instructions until the user enters some sentinel value
Pattern: Get value(s) from the user for the variable(s) in the test condition while the test condition is true { Do some set of instructions Get value(s) from the user for the variable(s) in the test condition }
This algorithm implies that there can be multiple test conditions involving multiple variables. Usually, however, there will only be one of each. In the program presently under discussion 'Price' is the variable and "Price != -1" is the test condition.

We can use this general algorithm or pattern to write a more specific algorithm for any problem involving user input and a loop that ends with a sentinel value input by the user. In fact, that is how the correct algorithm (a few paragraphs above) for the discounted price calculation was written. Here we repeat the algorithm and compare its instructions with the general instructions found in the pattern:

Get Price corresponds to Get a value from the user for the
variable(s) in the test condition

while Price != -1 corresponds to WHILE the test condition is true
(It is true that 'Price' is not equal to -1)

Discounted Price =
    Price * Discount
Output Discounted Price
corresponds to      Do a set of instructions

Once you have an algorithm in a form that is both correct and close to what a computer needs, it is easy to translate that algorithm into code. Below is the C++ code for the "Friday the 13th" Problem. Make sure you understand how all the lines were coded.

You will be assigned many programs of this type, both in this course and in any future programming you do. Take advantage of this pattern. After you have coded for awhile, this pattern (and the other patterns we are about to learn) will become second nature to you and you won't need to specifically review them each time you code. For now, however, while the idea is still new to you and you are likely to forget some aspect of the algorithm, always review this pattern and the other patterns below before starting to code.


Topics Covered in the "Essentials of C++"
The While Loop
Avoiding Infinite Loops Caused by Invalid Data Entry

Top of Section Main Menu Next Section