Schedule‎ > ‎

06B: Indefinite Loops and Do-While Loops

Indefinite Loops

Learner Outcomes

At the end of the lesson the student will be able to:

  • Use sentinel values to terminate a loop
  • Describe the advantages of using a Boolean variable to control a loop
  • Use do-while statements to repeat sections of code
  • Develop strategies for processing input and handling errors


    ^ top

    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.

    ^ top

    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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    
    void setup() {
    Serial.begin(9600);
    }

    void loop() {
    double balance = 0;
    double target = 0;
    double 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;

    cout << "Year\tBalance" << endl;

    int year = 0;
    cout << year << '\t' << balance << endl;
    while (balance < target) {
    year++;
    double interest = balance * rate / 100;
    balance = balance + interest;
    cout << year << '\t' << balance << endl;
    }
    cout << "Target amount of $" << target << " reached after " <<
    year << " years" << endl;
    }

    Note: set your Serial Monitor to something besides "No Line Ending".

    Try It: Indefinite Loops (3m)

    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 ________.

    ^ top

    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
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    
    const int INPUT_PIN = 2;
    void setup() {
    Serial.begin(9600);
    pinMode(INPUT_PIN, INPUT_PULLUP); //no button press = HIGH
    }
    void loop() { cout << "Please press the button to continue..." << endl; boolean ready = false; while (!ready) { if (digitalRead(INPUT_PIN) == LOW) { //wait for button press = LOW ready = true; } } cout << "Thanks!" << 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.
    • int loop_count = 0;
      while (!ready) {
         // ... check for the button
        loop_count++;
        delay(100);
      }
      
    • The 100ms delay slows down the loop
    • Long delays can make the button laggy
    • After the button push the count tells you how many tenths of seconds you spent waiting

    Example Application Using a Sentinel Value (aka flag or signal) for the Loop Test

    https://05d21547-a-62cb3a1a-s-sites.googlegroups.com/site/cs11mfall2017/schedule/decision-digital/button2_bb.png?attachauth=ANoY7cr_PXf7RtKEFW80ngwPCtWO5SYinmPLhrSzzhUMTv2nLnwtsBhq4CAmmRYTc0Xvx4YTLkF0DndOgnChca2CkMSegoE28sgyKpAxskVj8j-PCcmgaQMxGc1vk7ReXL0fNQlvHJ4CwqW0_lkAO8Uknz6GhvPgbTA5oKGgSoVNtWm3jxq0RWkhf-fnYCQRR9nvNM2YMJwf1b2W9XxHRTDEmYqKTy9vHMzqpymhaZ-2IrUxYggkDjpWpySsNd1SE9AdhE-FKyI9&attredirects=0

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    const int INPUT_PIN = 2; 
    
    void setup() {
    	Serial.begin(9600);
    	pinMode(INPUT_PIN, INPUT_PULLUP);  //button not pressed = HIGH
    }
    
    void loop() {
    	cout << "Please press the button to continue..." << endl;
    	boolean ready = false;
    	int loop_count = 0;
    	while (!ready) {   //loop here until the button is pressed
    		if (digitalRead(INPUT_PIN) == LOW) {
    			ready = true;
    		}
    		loop_count++;
    		delay(100);
    	}    //end of the while loop
    	cout << "I waited " << loop_count/10.0 << " seconds." << endl; 
    	delay(1000);
    }
    

    Check Yourself

    1. What happens when you increase the delay inside the while loop to 10000? 
    2. How much time does the program say it waits if you hold the button down?

    ^ top

    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

    credit

    Activity: Maximum and Minimum Values

    1. Students line up and each student chooses a number between one and 100.
    2. Start at one end of the line and each student passes the maximum-value-so-far to the next student in line.
    3. Repeat for the minimum value.

    Activity: Algorithm for Maximum Value

    1. Write down the algorithm for finding the maximum value in psuedocode. (3m)
    2. Review your algorithm with another student.

    Activity Check

    1. The initial minimum or maximum value in a series is the ________ value.
    2. To compare if the current value is smaller or larger than the current value, we use an ________statement.
    3. Unless we know the number of values in advance, we collect the input with a(n) ________ loop.
      1. for
      2. while
      3. counting
      4. indefinite

    Example of Finding a Maximum Value (Squeeze Test)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    #define SENSOR       1 
    #define LED 5

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

    void loop() {
    int sample;
    int maximum = 0;
    boolean testing = true;
    cout << "Squeeze test! Press any key to restart." << endl <<
    "Start with sensor squeezed" << endl;
    while (testing) {
    sample = analogRead(SENSOR);
    cout << "read sensor is " << sample << endl;
    if (sample > maximum) {
    maximum = sample;
    cout << "New maximum: " << maximum << endl;
    }
    if (Serial.available()) {
    Serial.read();
    testing = false;
    }
    delay(1000);
    } //end of while loop
    }


    ^ top

    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. Your program must make a decision:
    • Too cold: Heater on, A/C off
    • Just right: Heater off, A/C off
    • Too hot: Heater off, A/C on
    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
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    #define SENSOR       1 
    #define THRESHOLD 600

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

    void loop() {
    boolean pressed = false;
    boolean released = false;
    cout << "Squeeze the pad to continue... " << endl;
    while (!pressed || !released) {
    int value = analogRead(SENSOR);
    if (value > THRESHOLD) {
    pressed = true;
    }
    if (pressed && value < THRESHOLD) {
    released = true;
    }
    } //end of while loop
    cout << "Okay!" << endl;
    }

    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

    ^ top

    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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
    int loop() {
        float input = 0.0; // initialize value
        do {
            cout << "Enter a positive number: ";
            cin >> input;
            if (input <= 0.0) {
                cout << "You must enter a positive number" << endl;
            }
        } while (input <= 0.0); // test condition at end
        cout << "You entered: " << input << endl;
    
        return 0;
    }
    

    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 ________.

    ^ top

    Exercise 1: Sensor Calibration

    To get the best accuracy out of a sensor you sometimes need to calibrate it. The calibration of a sensor usually means finding the maximum and minimum readings that the sensor can actually make. In this exercise you'll use the circuit pictured to calibrate and read the photosensor. 

    Specifications

    1. Start with a loop that calibrates the sensor until the Arduino receives a key press and save your project as calibration.
    2. #define SENSOR       0 
      
      void setup() {
        Serial.begin(9600);
        analogReference(DEFAULT);
      }
      
      void loop() {
        bool keypress = false;
        int reading;
        Serial.print("Calibrate the sensor and press any key...");
        while (! keypress) {
          if (Serial.available()) {
            Serial.read();
            keypress = true;
          }
          reading = analogRead(SENSOR);   
        }
        Serial.println("done.");
      
        delay(1000);
      }
      
    3. Before the while loop, declare two variables of type int named max and min and initialize the variables:
      int max = 0;
      int min = 1023;
    4. Compile your code to make sure you declared the variables correctly.
    5. Inside the loop compare the readings to max and min and keep track of the maximum and minimum values.
      While running the code, place your finger over the sensor to make it as dark as possible. Then shine a light (like a flashlight) into the sensor to make it as bright as possible. Once you've done this send a key to the serial port. 
    6. After the loop print the maxreading and minreading values. Do they make sense?
      max should be greater than min 
    7. If your serial monitor prints out multiple times (as if there were multiple key inputs),  don't worry about it.  Continue to the next step.
    8. Now make another "keypress" loop after the first loop. This time make it a do/while loop:
    9. keypress = false;
      do {
          if (Serial.available()) {
            Serial.read();
            keypress = true;
          }
          reading = analogRead(SENSOR);   
        } while (! keypress);
    10. In this loop you should read the light level and print it as a floating point number that is a percentage of the calibrated sensor readings  (If reading == max, then percentage is 100%.  If reading == min, then percentage is 0%).  Declare a new variable:  double scaledPercentage.  Use this formula:
               scaledPercentage = 100.0 * (reading - min) / (max - min);
             Print scaledPercentage out. 
         11.  Save your calibration.ino source code and submit to Canvas.  Answer the following questions in the comment section of Canvas.

        Q1:  What does it mean to calibrate a sensor?

        Q2:  Why do we want to calibrate a sensor?

        Q2:  What is the point of scaling the reading?

    When finished please help those around you.

    ^ top

    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 109-112
    • 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

    7. Translate the algorithm to C++ and test the C++ code

    • When we are sure the algorithm works, we write the C++ code
    • Then we compile and test with some typical values
    • The complete program is shown below
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    
    void setup() {
    Serial.begin(9600);
    }


    void loop() {
    cout << "I will add up numbers for you" << endl;
    cout << "Enter the first value (0 to exit): " << endl;
    float value;
    cin >> value;
    float total = value;
    float highest = value;
    while (value != 0) {
    cout << "Enter the next value (0 to exit): " << endl;
    cin >> value;
    if (value != 0) {
    total = total + value;
    if (value > highest) highest = value;
    }
    }
    cout << "The total is " << total << " and the highest value is " << highest << endl;
    delay(1000);
    }

    ^ top

    06B Exercise 2:  Develop a Loop Program

    With your assigned partner,  follow the 7 steps

    to develop a loop to solve the problem: For a list of laptop prices,  display the average price, highest and lowest prices.

    (Refer to 06B Notes or Slides for examples)
    Grading:  14 pts.  2 points per step.  Steps 1-6 get turned in on paper.  Step 7 gets turned into Canvas.

    Be sure to write your name and your partner’s name on your paper.  You can submit one set of paper for the two of you.  You BOTH must submit the code to Canvas.  Call your program laptop.ino

    1. Decide what work must be done inside the loop

    2. Write the loop condition

    3. Choose the loop type

    4. Initialize the loop variables

    5. Process the loop results

    6. Trace the loop with example values

    7. Translate the algorithm to C++ and test the C++ code

    Sample output from your program:

    Enter prices for laptops
    Enter the first value (0 to exit):
    You entered: 500.00
    Enter the next value (0 to exit):
    You entered: 2000.00
    Enter the next value (0 to exit):
    You entered: 859.00
    Enter the next value (0 to exit):
    You entered: 0.00
    The average is 1119.67 highest value is 2000.00 lowest value is 500.00
    Enter prices for laptops
    Enter the first value (0 to exit):



    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) == HIGH) {
          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?

    ^ top

    Wrap Up and Reminders

    • For the next homework, see the schedule
    • When class is over, please shut down your computer.
    • Complete unfinished exercises from today before the next class meeting

    ^ top

    Subpages (1): Calibration