Iteration Case Studies   
Case Study 1: Count-Controlled Loops
Case Study 2: Sentinel-Controlled Loops
Case Study 3: Nested Control Structures

Case Study 4: Nested Loops

Formulating Algorithms: Case Study 1 (Count-Controlled Repetition)

Consider the following problem statement:

A class of ten students took an exam, with scores (integer) ranging from 1 to 100.  Determine the class average.

The class average is equal to the sum of the grades divided by the number of students. The algorithm for solving this problem on a computer requires input of each of the grades, calculating the average, and displaying the result.

This technique uses a variable called a counter to control the number of times a set of statements should execute. In this example, repetition terminates when the counter exceeds 10.

Initialize total to zero
Initialize grade counter to one

While grade counter is less than or equal to 10
     Input the next grade
     Add the grade to the total
     Add one to the grade counter
End While

Set the class average to the total divided by 10
Print the class average

Lines 170-175 perform the repetition part of the program. While the condition gradeCounter <= 10 is True, the four statements in the loop body are executed. With each iteration of the loop, gradeCounter is incremented by one. Eventually, counter is assigned the value eleven, which causes the loop-continuation test to become False, thus terminating the loop, and displaying the average.

Here is the same program using a For loop.  Notice that the loop control variable (gradeCounter) does not have to be explicitly initialized or incremented, and that the calculation of the average requires division by gradeCounter minus 1.

Demo


Formulating Algorithms with Top-down, Stepwise Refinement: Case Study 2 (Sentinel-Controlled Repetition)

Let us generalize a class average problem. Consider the following problem:

Develop a class averaging program that will process an arbitrary number of grades each time the program is run.

In the statement, no indication is given of how many grades are to be entered. The program must process an arbitrary number of grades. How can the program determine when to stop the input of grades? How will it know when to calculate and display the class average?

One way to solve this problem is to use a special value called a sentinel value (also called a signal value, a dummy value, or a flag value) to indicate "end of data entry." The user types grades in until all legitimate grades have been entered. The user then either types the sentinel value to indicate that the last grade has been entered or presses a particular button to indicate that the data entry is complete. Sentinel-controlled repetition is often called indefinite repetition because the number of repetitions is not known before the loop begins executing.

Clearly, the sentinel value must be chosen so that it cannot be confused with an acceptable input value. Because grades on an exam are normally nonnegative integers, -1 would be an acceptable sentinel value for this problem. Thus, a run of the class average program might process a stream of inputs such as 95, 96, 75, 74, 89 and -1. The program would then compute and display the class average for the grades 95, 96, 75, 74 and 89 (-1 is the sentinel value, so it should not enter into the averaging calculation).

We approach the class average program with a technique called top-down, stepwise refinement, a technique that is essential to the development of well-structured programs. We begin with a pseudocode representation of the top:

Determine the class average for the quiz

The top is a single statement that conveys the overall function of the program. As such, the top is, in effect, a complete representation of a program. Unfortunately, the top (as in this case) rarely conveys a sufficient amount of detail from which to write the program. So we begin the refinement process. We divide the top into a series of smaller tasks listed in the order in which they need to be performed This results in the following first refinement

Initialize variables
Input, sum, and count the exam grades
Calculate and display the class average

Here, only the sequence structure has been used--the steps listed are to be executed in order, one after the other.

To proceed to the next level of refinement (i.e., the second refinement), we commit to specific variables. We need a running total of the numbers, a count of how many numbers have been processed, a variable to receive the value of each grade as it is input and a variable to hold the calculated average. The pseudocode statement

Initialize variables

may be refined as follows:

Initialize total to zero
Initialize counter to zero

Notice that only variables total and counter need to be initialized before they are used, the variables average and grade (the calculated average and the user input) need not be initialized because their values will be written over as they are calculated or input.

The pseudocode statement

Input, sum, and count the exam grades

requires a repetition structure (i.e., a loop) that successively inputs each grade. Because we do not know in advance how many grades are to be processed, we will use sentinel-controlled repetition. The user will type legitimate grades in one at a time. After the last legitimate grade is typed, the user will type either the sentinel value or press a button. The program will test for the sentinel value after each grade is input and will terminate the loop when the sentinel value is entered by the user. The second refinement of the preceding pseudocode statement is then

Input the first grade (possibly the sentinel)
While the sentinel has not been entered
     Add this grade to the running total
     Add one to the grade counter
     Input the next grade (possibly the sentinel)
End While

Notice that in pseudocode, we do not write End While to terminate the body of the repetition structure. At this stage, we need not be concerned about what specific loop will be used. We simply indent all these statements under the While to show that they all belong to the While.

The pseudocode statement

Calculate and display the class average

may be refined as follows:

If the counter is not equal to zero
     Set the average to the total divided by the counter
     Display the average
Else
     Display "No grades were entered"
End If

Notice that we are being careful here to test for the possibility of division by zero-a fatal logic error that if undetected would cause the program to fail. The complete second refinement of the pseudocode for the class average problem is shown below.

Initialize total to zero
Initialize counter to zero

Input the first grade (possibly the sentinel)

While the sentinel has not been entered
     Add this grade to the running total
     Add one to the grade counter
     Input the next grade (possibly the sentinel)
End While

If the counter is not equal to zero
     Set the average to the total divided by the counter
     Display the average
Else
     Display "No grades were entered"
End If

Testing and Debugging Tip 

When performing division by an expression whose value could be zero, explicitly test for this case and handle it appropriately in your program (such as printing an error message) rather than allowing the fatal error to occur.

Note the references in the algorithm to a total and a counter. A total is a variable used to accumulate the sum of a series of values. A counter is a variable used to count-in this case, to count the number of grades entered. Variables used to store totals should normally be initialized to 0 before being used in program; otherwise the sum could contain previously stored values (often called garbage values). Although Visual Basic initializes Integer types to 0, it is a good practice to explicitly initialize total variables to 0. Counter variables are normally initialized to zero or one, depending on their use.

This algorithm was developed after only two levels of refinement. Sometimes more levels are necessary. The next step is to convert the pseudocode to Visual Basic. The program code is shown below.

Demo

Common Programming Error 

Using floating-point numbers in a manner that assumes they are represented precisely can lead to incorrect results. Floating-point numbers are represented only approximately by most computers. Decimal will handle monetary amounts precisely.

Type String is also introduced in this example. A String is a sequence of characters enclosed in a set of double quotes "".

Function InputBox is used to input the first grade (line 171). The While provides the repetition by executing the lines

gradeTotal += grade
gradeCounter += 1
grade = InputBox("Enter grade " & gradeCounter + 1 & " (-1 to end): ")

The first statement adds the grade and gradeTotal and stores the result into gradeTotal. As each grade is input, gradeCounter is incremented by one. The last line inputs the next grade.

The If/Then/Else determines the proper action to take if counter is zero (which occurs if the user enters -1 on line 171). If counter is not zero, the line

lblGradeAverage.Text = gradeTotal / gradeCounter

is executed. The floating-point division operator, /, is used to get a floating-point result from the division. We do not use the Integer division operator, \, because it returns a whole number (i.e., a number without a decimal place).

Despite the fact that floating-point numbers are not always "100% precise," they have numerous applications. For example, when we speak of a "normal" body temperature of 98.6° we do not need to be precise to a large number of digits. When we view the temperature on a thermometer and read it as 98.6°, it may actually be 98.5999473210643°. The point here is that calling this number simply 98.6° is fine for most applications.

Another way floating-point numbers develop is through division. When we divide 10 by 3. the result is 3.3333333... with the sequence of 3s repeating infinitely. The computer allocates only a fixed amount of space to bold such a value, so clearly the stored floating-point value can only be an approximation.

 


Formulating Algorithms with Top-down, Stepwise Refinement: Case Study 3 (Nested Control Structures)

In this case study we will see the only other structured way control structures may be combined, namely through nesting of one control structure inside another.

Consider the following problem statement:

A college offers a course that prepares students for the state licensing exam for real estate brokers.  Last year ten of the students who completed this course took the licensing exam.  The college wants to know how well its students did on the exam.  You have been asked to write a program to summarize the results.  You have been given a list of ten students.  Each name is followed by a P if the student passed, or an F is the student failed.

Your program should analyze the results of the exam as follows:

  1. Input each exam result (P or F).  Display the message "Enter result" to prompt for data entry.

  2. Count the number of passes and fails.

  3. Display a summary of the exam results, indicating the number of students who passed and the number who failed.

  4. If more than eight students passed the exam, print the message "Time to raise tuition again!".

After reading the problem statement carefully, the following observations can be made (in no particular order):

  1. The program must process exam results for 10 students, so a count-controlled loop is appropriate.  However, be sure to use a constant for the number of students because it may change in the future.

  2. Each exam result is a String--either a P or an F.  Each time a value is input for a result, a test must be made to ensure that the value is a P or an F. 

  3. Two counters store the exam results--one to count the number of students who passed  and another to count the number who failed.

  4. After the program has processed all the exam results it must determine if more than eight students passed.

Let us proceed with top-down, stepwise refinement. We begin with a pseudocode representation of the top.

Analyze exam results and decide if a tuition increase is supported

Once again, it is important to emphasize that the top is a complete representation of the program, but several refinements are likely to be needed before the pseudocode can be naturally evolved into a program. Our first refinement is

Initialize variables
Input the ten exam grades and count passes and failures
Print a summary of the results and decide if tuition should be raised

Here, too, even though we have a complete representation of the entire program, further refinement is necessary. We now commit to specific variables.  Counters are needed to record the passes and failures.  A counter (called a loop control variable) controls the looping process and a variable stores the user input. The pseudocode statement

Initialize variables

may be refined as follows:

Initialize passes to zero
Initialize failures to zero
Initialize student counter to one

The pseudocode statement

Input the ten exam grades and count passes and failures

requires a loop that inputs the result of each exam.  Here it is known in advance that there are ten exam results, so a count-controlled loop is appropriate.  Inside each loop (nested within the loop) we can use an If/Then/Else to determine whether each exam result is a pass or fail, and the structure increments the appropriate counter.  The refinement of the preceding pseudocode statement is then

While student counter is less than or equal to ten
     Input the next exam result

     If the student passed
          Add one to passes
     Else
          Add one to failures
     End If

     Add one to student counter
End While
 

Notice the use of blank lines to set off the If/Else control structure to improve readability.

The pseudocode statement

Print a summary of the results and decide if tuition should be raised

can be refined as follows:

Print the number of passes
Print the number of failures

If more than eight students passed

     Print "Time to raise tuition again!"
End If

The complete second refinement appears below. Notice that blank lines are used to separate the nested repetition structures for program readability.

Initialize passes to zero
Initialize failures to zero
Initialize student counter to one

While student counter is less than or equal to ten
     Input the next exam result

     If the student passed
          Add one to passes
     Else
          Add one to failures
     End If

     Add one to student counter
End While

Print the number of passes
Print the number of failures

If more than eight students passed

     Print "Time to raise tuition again!"
End If

The While loop inputs and processes the ten exam results.  The If/Then/Else is a nested control structure because it is enclosed within the While.  The condition tests if the String variable result is equal to "P", and if so, it increments passes by 1.  Otherwise, failures is incremented by 1.

Now we convert the pseudocode algorithm to a Visual Basic program. The GUI is shown below, followed by the code.  In the code we introduce the Beep statement, which sounds a beep through the computer speaker.  Note that a For/Next loop was not used since the loop control variable is not incremented in the case of invalid input.


Demo




 


Formulating Algorithms with Top-down, Stepwise Refinement: Case Study 4 (Nested Loops)

In this case study we will see another type of nesting.

Consider the following problem statement:

Write a program that draws a square of * characters in the command window. The side of the square (i.e., the number of * characters to be printed side by side) should be input by the user and should be in the range 1 through 20.

Your program should draw the square as follows:

  1. Input the side of the square.

  2. Validate that the side is in the range 1 through 20.

  3. Use repetition to draw the square on the form.

After reading the problem statement carefully, the following observations can be made (in no particular order):

  1. The program must draw n (the value input by the user) rows each with n * characters. Count-controlled repetition will be used.

  2. Each time a value is input for the side, a test must be made to ensure that the value is in the range 1 through 20.

  3. Three variables will be used--one that represents the side of the square, one that represents the row where each * will appear, and one that represents the column where each * will appear. 

Let us proceed with top-down, stepwise refinement. We begin with a pseudocode representation of the top.

Draw a square of * characters in the command window

Once again, it is important to emphasize that the top is a complete representation of the program, but several refinements are likely to be needed before the pseudocode can be naturally evolved into a program. Our first refinement is

Initialize variables
Input the side of the square.
Validate that input is within the proper range
Print the square

Here, too, even though we have a complete representation of the entire program, further refinement is necessary. We now commit to specific variables. A variable is needed to store the side, a variable is needed to store the row where printing is occurring, and a variable is needed to store the column where the printing is occurring. The pseudocode statement

Initialize variables

may be refined as follows:

Initialize side to the value input
Initialize row to one
Initialize column to one

The pseudocode statement

Input the side of the square

requires that a value be obtained from the user. The pseudocode statement

Validate that input is within the proper range

may be refined as

If side is greater than 0 and less than or equal to 20 then

which explicitly tests whether side is greater than 0 and whether side is less than or equal to 20. If the first condition (i.e., side greater than 0) is true, the next condition (i.e., side is less than or equal to 20) is tested. If the first condition is false, the second condition is tested only if you use an AndAlso.

The pseudocode statement

Print the square

can be implemented by using nested loops to draw the square. Here it is known in advance that there are precisely n * characters, so count-controlled repetition is appropriate. One loop will control the row on which each * is drawn. This loop does not do the actual drawing. Inside this loop (i.e., nested within this loop) a second loop will draw each individual *. The refinement of the preceding pseudocode statement is then

While row is less than or equal to side
     Set column to one

     While column is less than or equal to side
          Print *
          Increment column by one
     End While

     Print
     Increment row by one
    
End While

After column is set to one, the inner loop executes to completion (i.e. until column exceeds side). Each iteration of the inner loop results in a single * being printed. Print * specifies that the next printing operation is to occur on the row. Variable row is incremented by one. If the outer loop condition allows the body of the loop to be executed, column is reset to one because we want the inner loop to execute again and print another row of * characters. Print specifies that the next printing operation is to occur on the next line. Variable row is incremented by one. This process is repeated until the value of row exceeds side.

The complete second refinement appears below. Notice that blank lines are used to separate the nested repetition structures for program readability. Also notice row is initialized after the nested If statements determine that row is valid. This was done for performance reasons-why take the time to initialize rows unless we are going to use rows?

Initialize side to the value input|

If side is greater than 0 and less than or equal to 20 then
     Initialize row to one
     While row is less than or equal to side
          Set column to one

          While column is less than or equal to side
               Print *
               Increment column by one
          End While

           Print carriage return/line feed
          Increment row by one
     End While
Else
     Print "Side is out of range"
End If

Now we convert the pseudocode algorithm to a Visual Basic program. The GUI is shown below, followed by the output and the code.

Demo