Schedule‎ > ‎

### 06B: Indefinite Loops and Do-While Loops

• Questions from last class?

^ top

## 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

• 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;
// ... 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

#### ```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 5void 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

2. ```#define SENSOR       0

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

void loop() {
bool keypress = false;
Serial.print("Calibrate the sensor and press any key...");
while (! keypress) {
if (Serial.available()) {
keypress = true;
}
}
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()) {
keypress = true;
}
} 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?

^ 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:

Add the first value to the total
Set the highest value as the first value
Add the second value to the total
If the second value is higher than the highest, set the highest to the second 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:

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

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

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;
}
}
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

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