Home‎ > ‎CS 11M‎ > ‎

Indefinite Loops

Questions, Answers and Review

  • Questions from last class?
  • Questions about homework?

Indefinite Loops

About Indefinite Loops

  • Loops are called indefinite loops when you do not know in advance how many time the loop will execute
  • This behavior is different from a counting loop where you know how many times the loop will execute before the loop starts
  • With an indefinite loop we can solve a new set of problems
  • Most problems solved with indefinite loops make use of while statements

Check Yourself

  1. True or false: with an indefinite loop, you often know in advance how many times the loop will repeat.
  2. True or false: the best looping statement for an indefinite loop is a for statement.
  3. True or false: a counting loop is a good example of an indefinite loop.

Indefinite Loop Example

  • As an example of an indefinite loop, let us look at the problem of compounding interest
  • If we invest $10,000 at 5% interest, compounded annually, our savings grow like this:
    Year Balance
    0 $10,000
    1 $10,500
    2 $11,025
    3 $11,576.25
    4 $12,155.06
    5 $12,762.82
  • How many years does it take for the initial investment to double?
  • To solve this problem we can use a while loop:
    float balance = 10000;
    int year = 0;
    while (balance < 20000) {
        year++;
        float interest = balance * 0.05; // 5% interest
        balance = balance + interest;
    }
    
  • We can make the loop work for any interest rate, starting balance and target amount as shown below

Program with an Indefinite Loop

#include <ArduinoSTL.h>

using namespace std;

void setup() {
  Serial.begin(9600);
}

void loop() {
  float balance = 0;
  float target = 0;
  float rate = 0;

  cout << "Enter the starting balance:" << endl;
  cin >> balance;
  cout << "Enter the interest rate as a percent:" << endl;
  cin >> rate;
  cout << "Enter the target amount:" << endl;
  cin >> target;

  int year = 0;
  cout << year << '\t' << balance << endl;

  while (balance < target) {
    year++;
    float interest = balance * rate / 100;
    balance = balance + interest;
    cout << year << '\t' << balance << endl;
  }

  cout << "Target amount of $" << target 
    << " reached after " << year << " years" << endl;
}

Try It: Indefinite Loops

Run the above program and answer the following questions.

  1. If the interest rate is 5%, the number of years before an investment doubles is ________.
  2. The number of years for an investment of $10,000 to triple at 5% interest is ________ .
  3. If the interest rate is 1%, the number of years for an investment of $10,000 to double is ________.
  4. Can you easily predict how times the loop in the above program would repeat to double an investments at a certain interest rate? If so, how?

Waiting for an Event 

  • A common use for an indefinite loop is to wait for an event, like a button press
  • The program waits by looping around until something happens
  • This is called busy waiting
  • We don't know how long the program will wait so we use an indefinite loop as shown below
#include <ArduinoSTL.h>

using namespace std; 

const int button = 12; 

void setup() {
  Serial.begin(9600);
  pinMode(button, INPUT_PULLUP);
}

void loop() {
  cout << "Press the button to continue." << endl;

  bool go_for_it = false;
  while (! go_for_it) {
    if (digitalRead(button) == LOW) {
        go_for_it = true;    
    }
  }

  cout << "Okay!" << endl;
  delay(1000);
}

Keeping Track of Time

  • What if we needed to know how long we waited?
  • You can use a variable to keep track of time.
  • Consider changing the above loop to:
  int ticks = 0;
  while (! go_for_it) {
    if (digitalRead(button) == LOW) {
        go_for_it = true;    
    }
    delay(100);
    ticks++;
  }
  cout << "I waited for " << ticks * 100 << " ms" << endl;
  • The 100ms delay slows down the loop
  • Long delays can make the button laggy
  • After the button push the count tells you how many milliseconds you spent waiting

Example Application Using a Sentinel Value for the Loop Test

#include <ArduinoSTL.h>

using namespace std;

void setup() {
  Serial.begin(9600);
}

void loop() {
  cout << "Breaker breaker, come back, over." << endl;

  string wrd;
  while (wrd != "over") {
    cin >> wrd;
    cout << wrd << " ";
  }

  cout << endl;
}

Maximum and Minimum Values

  • Sometimes we need to find the maximum or minimum number of a group
  • For instance we may want to know the highest score on a test
  • We use a loop to read a sensor repeatedly
  • As we get each new reading, we test to see if it is larger than the previous maximum
    if (score > max) {
        max = score;
    }
    
  • We further explore the algorithm in the following activity

 Example of Finding a Maximum Value (Squeeze Test)

#include <ArduinoSTL.h>

using namespace std;

const int pressureSensor = A1; 
const int rightButton = 12; 

void setup() {
  Serial.begin(9600);
  pinMode(rightButton, INPUT_PULLUP);
}

void loop() {
  cout << "Measuring the pressure sensor. Press the RIGHT button to proceed." << endl;

  int maximum = 0;
  while (digitalRead(rightButton) == HIGH) {
    int reading = analogRead(pressureSensor); 
    if (reading > maximum) {
      maximum = reading;         
    }
  }

  cout << "The maximum pressure was " << maximum << endl;
  delay(1000);
}

Checking For Complex Input

Sometimes you want a sensor to behave as if it were a button. When the reading goes above or below a predefined point you want the button to "click." Think of a thermostat, the temperature sensor gives you an analog value. 
The program below shows how you can use the squeeze sensor to work like a momentary button. The if statement waits until you have squeezed hard enough to trigger a press and sets the pressed variable to true. The if statement below it waits for the value to fall below the threshold and sets the released variable to true. The loop waits for the pad to be "pressed" and then "released" 

Example Using Boolean Values to Check Conditions

#include <ArduinoSTL.h>

using namespace std;

const int pressureSensor = A1; 
const int threshold = 200; 

void setup() {
  Serial.begin(9600);
}

void loop() {
  cout << "Measuring the pressure sensor." << endl;

  int maximum = 0;
  bool pressed = false;
  bool released = false;

  while (!pressed || !released) {
    int reading = analogRead(pressureSensor); 
    if (reading > maximum) {
      maximum = reading;         
    }
    if (reading > threshold) {
      pressed = true;
    }
    else if (pressed && reading < threshold) {
      released = true;
    }
  }
  cout << "The maximum pressure was " << maximum << endl;
  delay(1000);
}

Check Yourself
  1. True or false: code like the above contains an indefinite loop.
  2. True or false: the above has two tests for the pass condition.
  3. The purpose of an if-statement when validating input is to ________.
    1. initialize the input variable
    2. check for an input condition
    3. loop when an error is found
    4. print the value entered
  4. The purpose of an while-statement in the above example is to ________.
    1. initialize the input variable
    2. check for errors
    3. loop until a condition is found
    4. print the value entered

do-while Statements

  • Sometimes we want to execute the body of a loop at least once and perform the loop test after the body was executed
  • For this we can use the do-while (or just do) loop:
    do {
       statements
    } while (test); // loop test
    
  • Where:
    • statements: the statements to execute the first time and repeatedly while the test remains true
    • test: the test condition to evaluate
  • The loop test is placed after the body and executes at the end of the loop
  • The statements in the body of the loop always execute at least once
  • One common use of a do-while loop is to validate user input
  • The following code shows an example where we force the user to enter a positive value

Example do-while Loop Used to Validate Input

  float input;
  do {
    cout << "Enter a positive number:" << endl;
    cin >> input;
  } while (input <= 0.0); // test condition at end

  cout << "You entered: " << input << endl;

When to Use do-while Statements
  • Use the do-while loop when you want to force a minimum of one iteration
  • Note that you can accomplish the same control flow with a while loop
  • However, in some cases we can save a statement by using a do-while loop

Check Yourself

  1. True or false: the test of a do-while loop occurs at the end of the loop.
  2. True or false: the body of a do-while loop always executes at least one time.
  3. The reason to use a do-while loop, instead of a while loop, is to ________.

Exercise: while for for

#include <ArduinoSTL.h>

using namespace std;

void setup() {
  Serial.begin(9600);
}

void loop() {

  for (int i=0; i<10; i++) {
    cout << i << endl;
  }
        
}

Start with the code above. 

Specifications

  • Write a while loop the performs the same task as the given for loop. 
  • Can you see any difference between the while loop and the for loop?
    • Hint: What is the scope of the index variable? 

Turn In

  • Save your exercise as while-for-for.ino
  • Submit it with this week's assignment.
When finished work on the project.

How to Write a Loop

  • When your program needs to do the same commands repeatedly, you should consider writing a loop
  • We have covered several common situations in which to use loops:
    • Repeating a program or part of a program
    • Counting a series of items
    • Displaying a series of numbers or items
    • Processing a series of items, such as the characters in a string
    • Repeating a series of calculations to arrive at a goal
    • Processing a sequence of inputs
    • Validating input
  • In this section we look at a step-by-step procedure for developing a loop like that shown in the textbook on pages 154-156
  • As an example, let us solve the problem:

    From a series of numbers entered by a user, such as for cash register receipts, find the total and highest number.

1. Decide what work must be done inside the loop

  • If the commands to repeat are not obvious, start by writing down the steps you would take to solve the problem by hand
  • For our example, the steps are something like:

    Read the first value 
    Add the first value to the total 
    Set the highest value as the first value 
    Read the second value 
    Add the second value to the total 
    If the second value is higher than the highest, set the highest to the second value 
    Read the next value 
    Add this next value to the total 
    If this next value is higher than the highest, set the highest to this next value 
    ...

  • From these steps, look for the parts that are repeated and write them so they are uniform, like:

    Read the next value 
    Add this next value to the total 
    If this next value is higher than the highest, set the highest to this next value

  • These become the statements that go inside the loop
  • Thus you end up with psuedocode like:
    loop
        read the next value
        total = total + next value
        if next value > highest
            highest = next value
    

2. Write the loop condition

  • Decide what goal you want your loop to reach
  • For instance:
    • Has a counter reached the final value?
    • Has the user entered the last input value?
    • Has the loop reached a certain threshold?
  • For out example, we want to know if the user has entered the last value
  • Since we are totaling numbers, and we would not bother to enter the number zero, we can use zero as the sentinel value
  • Thus our test condition is something like:
    loop while the next value != 0
  • Remember that the test condition is about how to keep the loop going
  • When choosing a sentinel, we must make certain that the sentinel value is not used in the computation
  • For instance, entering a zero to exit the loop could end up being the highest value if all the numbers entered were negative
  • We correct this problem by adding an if statement that excludes the sentinel value from the computations
  • Thus our loop now looks like:
    loop while the next value != 0
        read the next value
        if next value != 0
            total = total + next value
            if next value > highest
                highest = next value
    

3. Choose the loop type

  • By this time you should have a good idea what your loop is doing
  • Decide on the loop statement as follows:
    1. If you know in advance of the loop how many times it repeats, use a for loop
    2. Otherwise, if the loop must be executed at least once, use a do-while loop
    3. Otherwise, use a while loop
  • For our example:
    1. The number of times the loop will execute is unknown before the loop starts
    2. There is no need to force the loop body to execute at least once
    3. Thus, we should use a while loop

4. Initialize the loop variables

  • For each of the variables used in the loop, determine what their first value must be
  • Usually, counter variables are set to 0 or 1 and totals to 0
  • In our example, the variables are:
    next value
    total
    highest
    
  • Both next value and total can be initialized to zero
  • However, we need to be careful about highest value
  • We cannot set it to zero because the user can enter negative numbers
  • For instance, if the user enters -1, -2 and then a 0 to exit, the highest value would compute as 0
  • A common strategy in this case is to set the highest value to the first value read
  • Thus our initialization looks like:
    read the first value
    total = first value
    highest = first value
    

5. Process the loop results

  • Sometimes this step is simply to use a variable computed in the loop
  • Other times you must do more computations with the variables from the loop
  • For our example, we only need to display the total and highest number
  • The psuedocode for our complete loop is:
    read the first value
    total = first value
    highest = first value
    loop while the next value != 0
        read the next value
        if next value != 0
            total = total + next value
            if next value > highest
                highest = next value
    Print total and highest
    

6. Trace the loop with example values

  • Before translating our algorithm to C++, we need to test it by hand with tracing
  • Write the variables used in the loop as headings across a page
  • On the first line under the headings, write the initial values
  • Execute the loop 3-5 times to check for errors
  • Pay especial attention when entering the loop the first time and when ending the loop
  • You can slightly modify the computations if it helps to test the loop
  • For our example, we can trace the execution as shown below 

    value total highest
    10 10 10
    20 30 20
    30 60 30
    -10 50 30
    0 50 30

  • The trace shows that total and highest are properly set by the algorithm

Summary

  • In this section we looked at using indefinite loops
  • With an indefinite loop, you do not know how many time the loop will execute ahead of time
  • Since you do not know how many times the user will repeat ahead of time, the loop is indefinite
  • An indefinite loop example was waiting for a button peress
  • The amount of time depends on the how long it takes a user to press the button, like:
    boolean ready = false;
    while (!ready) {
      if (digitalRead(INPUT_PIN) == LOW) {
        ready = true;
      }
    }
    Serial.println("Thanks!");
  • Another common use for indefinite loops is to process a sequence of inputs
  • Whenever we read a sequence of input values, we need to have some way of terminating the input loop
  • Since entering extra data each time through a loop is annoying, we discussed using a sentinel value to terminate the loop
  • A sentinel controlled loop looks for a sentinel value in the input data
  • A sentinel value is a special number (or other data) used to signal termination of a loop
  • We looked at how to sum numbers with a sentinel-controlled loop
  • Another common use for indefinite loops is input validation
  • Input validation combines a loop with one or more if statements
  • The loop repeats input until the user enters reasonable input
  • Since we do not know how many times the loop must execute ahead of time, the loop is indefinite
  • Another looping statement is the do-while loop, which tests the condition at the end of the loop body:
    do {
       statements
    } while (test); //loop condition
    
  • Testing at the end ensures a minimum of at least one iteration
  • Finally, we discussed a step-by-step procedure for developing loops

Check Yourself

Answer these questions to check your understanding. You can find more information by following the links after the question.

  1. What is an indefinite loop?
  2. How many times does an indefinite loop execute?
  3. How many years does it take to double $10,000 at 10% interest?
  4. What is a sentinel value?
  5. What is the advantage of using a sentinel value to terminate a loop?
  6. What is input validation?
  7. What is the difference between a while and a do-while loop?
  8. When designing a loop, how do you decide what work is done inside the loop?

Wrap Up and Reminders

  • When class is over, please shutdown your computer.
  • Complete unfinished exercises from today before the next class meeting
Comments