Schedule‎ > ‎

### 05A Complex Decisions and Counting Loops

• Questions from last class?
• Questions about labs or upcoming homework?

^ top

^ top

 Learner Outcomes At the end of the lesson the student will be able to: Recognize the correct ordering of tests in multiple branches Program conditions using Boolean operators and variables Avoid some common pitfalls when creating test conditions

^ top

### Multiple Alternatives

• By using collections of if-else statements, a program can distinguish between multiple alternatives

#### Program For a HandshakeTester

source:  123RF.com

 `void loop() ``{``                      ` `  ``int```` pressure = ````analogRead``(SENSOR);` ```  ````if (pressure < 100) {` ```    ````cout```` << “I can’t feel anything.“ << ````endl``;` ```  ````}else if (pressure < 500) {` ```    ````cout```` << “Light grip“ << ````endl``;` ```  ````}else if (pressure < 800) {` ```    ````cout```` << “Firm Grip“ << ````endl``;` ```  ````}else{` ```     ````cout```` << "Ouch!!“````  ``<< ``endl``;` `  ``}` ```  ````delay(1000);` `}`

#### Choosing Between Alternatives

• This program has four alternatives to choose from:
1. I can't feel anything.
2. Light grip.
3. Firm grip.
4. Ouch!!
• Note that the order that the alternatives are checked is important
• We can follow the alternatives in the flowchart shown below

#### Check Yourself

1. In the above program, what happens if the pressure sensor reads 423?
2. True or false? An elegant way to choose among multiple alternatives is to nest `if` statements in an `else` clause.
3. If `score = 85`, what is output by the following code fragment?
4. if (score >= 90)  {
cout << "You got an A" << endl;
}
else if (score >= 80)  {
cout << "You got a B" << endl;
}
5. In the above sequence of `if`-statements, the test condition of the first `if`-statement must be ________before the second `if`-statement executes.

^ top

### 4.2.2: When Order Matters

• In some cases, the order of the tests is not important
• IF all the tests used == then they can be done in any order
• Note that in the love tester the order of the tests is important to ensure that the right results are printed

#### Order Is Important

• If we rearranged the order of the `if-else` statements, we would get the wrong results
• For example, if we reversed the order of the tests:
```if (pressure < 800) {
cout << "Firm Grip" << endl;
}else if (pressure < 500) {
cout << "Light Grip" << end'}else if (pressure < 100) {
cout << "I can't feel anything" << endl;
}else{
cout << "Ouch!!" << endl;
}```
• This does not work because Firm Grip will always be printed out.
• Some tests will never be attempted

#### Importance of Using `if-else-if` Structure

• Note that we cannot remove the `else` portion of the structure like shown below:
```if (pressure < 100) {
cout << "I can't feel anything" << endl;}
if (pressure < 500) {
cout << "Light Grip" << endl;
}

if (pressure < 800) {
cout << "Firm Grip" << endl;
}```
• The conditions must be exclusive and we need the else-if conditions to ensure exclusivity
• Independent `if` statements may cause a single input to print several messages

#### Check Yourself

1. True or false? Order never matters in a sequence of `if` and `else` statements.
2. Suppose the sensor read -1 into the love tester program. What is printed?
3. How can the following code be simplified?
```if (price > 100) {
discount = price - 20;
} else if (price <= 100) {
discount = price - 10;
}
```

^ top

^ top

### 4.2.4: Nested Branches

• Nested `if-else` statements can be used when there are two (or more) levels of decision making.
• For example, consider the following two tax tables from 1992
• There is a different table for each marital status (decision 1)
• Once you have found the right table, you are taxed differently according to your income (decision 2)

#### Tax Table if Single

 If your status is Single and if the taxable income is over but not over the tax is of the amount over \$0 \$21,450 15% \$0 \$21,450 \$51,900 \$3,217.50 + 28% \$21,450 \$51,900 \$11,743 + 31% \$51,900

#### Tax Table if Married

 If your status is Married and if the taxable income is over but not over the tax is of the amount over \$0 \$35,800 15% \$0 \$35,800 \$86,500 \$5,370.00 + 28% \$35,800 \$86,500 \$19,566.00+ 31% \$86,500

#### Programming Two-Level Decisions

• When we program this two-level decision process, we often use two levels of `if` statements
• We say the income test is nested inside the test for filing status
• We can see this two-level decision in the flowchart shown below
• Also, we can examine and run the program from the code shown below
• Note that more complicated decisions may require deeper levels of nesting

#### Flowchart of Two-level Tax Decision Process

Develop a Flowchart of the Two-level Tax Decision Process in Teams on WhiteBoards

#### Program Computing Single and Married Tax Rates

 ```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 39 40 41 42 43 44 45 46 47 48 49 50 51 52535455 ``` ```void setup() { Serial.begin(9600);}void loop() { const double SINGLE_LEVEL1 = 21450.00; const double SINGLE_LEVEL2 = 51900.00; const double SINGLE_TAX1 = 3217.50; const double SINGLE_TAX2 = 11743.50; const double MARRIED_LEVEL1 = 35800.00; const double MARRIED_LEVEL2 = 86500.00; const double MARRIED_TAX1 = 5370.00; const double MARRIED_TAX2 = 19566.00; const double RATE1 = 0.15; const double RATE2 = 0.28; const double RATE3 = 0.31; int marital_status; double income; double tax; cout << "What is your income?" << endl; cin >> income; while (Serial.available()) { //put this after your cin statement Serial.read(); } cout << "Please enter 1 for single, 2 for married: " << endl; cin >> marital_status; while (Serial.available()) { //put this after your cin statement Serial.read(); } if (marital_status == 1) { if (income <= SINGLE_LEVEL1) { tax = RATE1 * income; } else if (income <= SINGLE_LEVEL2) { tax = SINGLE_TAX1 + RATE2 * (income - SINGLE_LEVEL1); } else { tax = SINGLE_TAX2 + RATE3 * (income - SINGLE_LEVEL2); } } else { if (income <= MARRIED_LEVEL1) { tax = RATE1 * income; } else if (income <= MARRIED_LEVEL2) { tax = MARRIED_TAX1 + RATE2 * (income - MARRIED_LEVEL1); } else { tax = MARRIED_TAX2 + RATE3 * (income - MARRIED_LEVEL2); } } cout << "The tax is \$"; cout << tax << endl;} ```

### Try It: Using Nested `if`-statements (8m)

We want to write a program to calculate a student's letter grade according to the following table:

greater than or equal to 90 A
less than 90 but greater than or equal to 80 B
less than 80 but greater than or equal to 70 C
less than 70 but greater than or equal to 60 D
less than 60 F
1. Copy the following program into the Arduino IDE editor and then compile and run the starter program to make sure you copied it correctly.
```void setup() {
Serial.begin(9600);
}

void loop() {
}```
2. Add code to get user input into a variable named `score` of type `double`. When you run the program after adding this code, the output should look like:
```Enter a score: 95.7
```

Make sure you declare the variable with a compatible data type. Note that the underlined numbers above shows what the user enters and is not part of your code. For more information see section 2.4.7: Input and Output.

3. First we will look at a series of `if` statements and see that `if` statements alone are not enough to solve this problem. Copy the following into your program after the input statements:
```String grade;
if (score >= 90) {
}
if (score >= 80) {
}
if (score >= 70) {
}
if (score >= 60) {
}
if (score < 60) {
}
```

Compile and run your modified program. There is a logic problem with this code. Each test condition needs to work over a range of values rather than with a single value.

4. One way to correct the problem is to nest an `if` statement inside of another `if` statement. To see how this works, modify your code to add nested `if` statements as shown below:
5. To test the range, the outer `if` statement tests the lower condition and the inner `if` statement tests the upper condition.

6. Compile and run your modified program to make sure you made the changes correctly. When you run the program, the output should look like:
```Enter a score: 80
B
```

Run your program a few times with different score to verify that any score displays the correct letter grade.

7. Save your `grader.ino` file because you will use it soon.
8. Be prepared to answer the following Check Yourself questions when called upon.

#### Check Yourself

1. True or false? You can nest if statements within another if statement.
2. If you are single and your taxable income is \$21,450, your tax is ________.
3. If you get a \$1000 per year raise and now make \$22,450, you now pay taxes of ________.
4. Some people object to higher taxes for higher incomes, claiming that you might end up with less money after taxes when you get a raise for working hard. The flaw in this argument is ________.

^ top

### 4.2.5: Boolean Variables

• Sometime we need to evaluate a logical condition in one part of a program and use it elsewhere
• To store a condition that can only be true or false, we use a Boolean variable
• Boolean variables are named after George Boole (1815-1864), a pioneer in the study of logic
• We specify a Boolean variable using the `bool` type, which can hold just one of two values: `true` or`false`
```bool isCool = true;
bool lies = false;
```
• Question: What type of tests does George Boole give? (answer)
• Question: How does George Boole order lunch? (see here)

#### Test Conditions and Boolean Values

• Remember that test conditions always evaluate to `true` or `false`
```if (num > 0)
```
• Thus we can use a boolean variable as a test condition
```bool isPositive = (num >= 0);
if (isPositive)
```
• Note that we do not need to add a relational expression to a boolean variable, like:
`if (isPositive == true) // avoid!`
• Since the boolean variable already evaluates to `true` or `false`, adding the `== true` is redundant
• Likewise, we do not need to use:
`if (isPositive != false) // avoid!`
• If we want to reverse the test condition, we can use the not (`!`) operator
`if (!isPositive)`
• We can see the use of a Boolean variable in the following example

#### Example Application Using a Boolean Variable

 ```1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ``` ```void setup() { Serial.begin(9600);}void loop() { double num; cout << "Enter a number:" << endl; cin >> num; bool isPositive = (num >= 0); cout << "The test evaluated to: " << isPositive << endl; if (isPositive) { cout << "The number was 0 or positive" << endl; } else { cout << "The number was negative" << endl; }} ```

#### Check Yourself

1. True or false: the number of values that can be stored in a Boolean data type are 3: true, false and null.
2. True or false: the Boolean data type is spelled `boolean` (with a lower case "b") in C++.
3. True or false: a test condition always evaluates to a Boolean value.
4. True or false: a Boolean variable can substitute for a test condition in an if-statement.

^ top

### 4.2.6: Logical Operators

• Sometimes we need to test for multiple conditions in our programs
• For example, we want to test if an age is between 18 and 25
• We need to test both that age >= 18 and age <= 25
• One way to make the tests is with nested if statements
```int age = 0;
cout << "Enter your age:" << endl;
cin >> age;
if (age >= 18)
{
if (age <= 25)
{
cout << "Correct age!" << endl;
} else {
cout << "Wrong age!" << endl;
}
} else {
cout << "Wrong age!" << endl;
}
```
• If the age entered is correct, like 19, we get the message, "Correct age!"
• If the age entered is not correct, like 15, we get the message, "Wrong age!"
• While this works, it is cumbersome to code and read
• A better approach is to combine test conditions with logical operators

#### Combining Test Conditions with Logical Operators

• logical operator, or Boolean operator, is an operator that treats operands as Boolean values (`true` or`false`)
• C++ has several logical operators, but we only need to use three to create any possible test condition
• These three operators are `and``or` and `not`, which are discussed below
• These logical operators are traditionally written as `&&` (`and`), `||` (`or`) and `! (not)`
• Both variants are legal under ANSI C++
• The words are easier to read but many C++ programmers still use the older form

#### Truth Tables for and, or and not

`and` (`&&`) Operator Truth Table
If expr1 is... And expr2 is... Then expr1 `and` expr2 is... Example Result
`true` `true` `true` `5 < 10 and 5 > 2` `true`
`true` `false` `false` `5 < 10 and 5 < 2` `false`
`false` `true` `false` `5 > 10 and 5 > 2` `false`
`false` `false` `false` `5 > 10 and 5 < 2` `false`
`or` (`||`) Operator Truth Table
If expr1 is... || expr2 is... Then expr1 `or` expr2 is... Example Result
`true` `true` `true` `5 < 10 or 5 > 2` `true`
`true` `false` `true` `5 < 10 or 5 < 2` `true`
`false` `true` `true` `5 > 10 or 5 > 2` `true`
`false` `false` `false` `5 > 10 or 5 < 2` `false`
`not` (`!`) Operator Truth Table
If expr is... Then `!` expr is... Example Result
`true` `false` `!true` `false`
`false` `true` `!(5 < 2)` `true`

#### Example Using Logical Operators

• We could rewrite our age test using an `and (&&)` operator like this:
```int age = 0;
cout << "Enter your age:" << endl;
cin >> age;
if (age >= 18 && age <= 25)
{
cout << "Correct age!\n";
} else {
cout << "Wrong age!\n";
}```
• Notice that the code is shorter and it is easier to follow the logic
• Another way to use logical operators to test the age is:
```int age = 0;
cout << "Enter your age:" << endl;
cin >> age;
if (age < 18 || age > 25)
{
cout << "Correct age!\n";
} else {
cout << "Wrong age!\n";
}```
• Many people confuse `&&` and `||` conditions, especially when learning about logical operators
• A value lies between 0 and 100 if the value is at least 0 and at most 100
• A value is outside that range if it is less than 0 or greater than 100
• There is no golden rule; we have to think carefully and test our conditions

#### Another Look at Truth Tables

• Note that most computers store `true` as `1` and `false` as `0`
• The NOT operator simply reverses its operand

#### Parenthesis

• Remember that a Boolean expression in an `if` statement must be enclosed in parenthesis
• Thus, an `if` statement with `&&` might look like:
`if ((guess != GUESS1) && (guess != GUESS2))`
• However, relational operators have a higher precedence than logical operators
• Thus, we can remove the inner parenthesis without affecting the meaning:
`if (guess != GUESS1 && guess != GUESS2)`
• However, if using parenthesis is easier to understand then use the extra parenthesis

#### Example Program with Logical Operators

 ```1 2 3 4 5 6 7 8 9 10 11 12 13 14 ``` ```void setup() { Serial.begin(9600); } void loop() { bool op1 = false, op2 = false; cout << "Enter true(1) or false(0) for two operands: " << endl; cin >> op1; cin >> op2; bool answer1 = op1 && op2; bool answer2 = op1 || op2; cout << op1 << " and " << op2 << " = " << answer1 << endl; cout << op1 << " or " << op2 << " = " << answer2 << endl; } ```

### Try It: Using Logical Operators (5m)

We previously used a nested if-statement to test multiple conditions. Often, a better approach is to use Boolean operators like `&&` and `||`.

1. Modify your `grader.ino` code from the last Try It to remove nested if statements and replace them with logical operators.
2. Compile and run your modified program to make sure you made the changes correctly. When you run the program, the output should look like:
```Enter a score: 80
B
```

Run your program a few times with different score to verify that any score displays the correct letter grade.

3. Save your `grader.ino` file to submit as part of the next exercise.
4. Be prepared to answer the following Check Yourself questions when called upon.

#### Check Yourself

1. Of the following groups ________ is larger.
1. Students wearing denim
2. Students wearing denim AND corrective lenses
2. Of the following groups ________ is larger.
1. Students wearing denim
2. Students wearing denim OR corrective lenses
3. Of the following groups ________ is larger.
1. Students wearing denim
2. Students wearing denim AND NOT corrective lenses
4. For the following code, the test condition evaluates to ________.
```bool denim = true;
bool lenses = false;
Serial.println(denim && lenses);
```
5. For the following code, the test condition evaluates to ________.
```int age = 21;
Serial.println(age >= 18 && age <= 25);
```
6. Of the following logical expressions, the test to see if `x` is between 1 and 10 (including 1 and 10) is________.
1. `(x >= 1 && x <= 10)`
2. `(1 <= x and x <= 10)`
3. `(x >= 1 || x <= 10)`
4. `(1 <= x or x <= 10)`

^ top

### Exercise 1 Multiple Alternatives (grader.ino)

In this exercise we test multiple alternatives in a program. As an example, we will calculate a student's letter grade according to the following table:

greater than or equal to 90 A
less than 90 but greater than or equal to 80 B
less than 80 but greater than or equal to 70 C
less than 70 but greater than or equal to 60 D
less than 60 F

#### Specifications

1. Complete the Try It: Using Nested if-statements if  you  haven't already.
2. In addition, complete the Try It: Using Logical Operators.  Before going on to step 3,  put step 1 & 2 into a comment block /*   */
3. Perhaps the most elegant solution is to nest an `if` statement in the `else` clause of the preceding `if`. Modify the series of `if` statements in `grader.ino` to include an `else` clause.

We are nesting `if` statements in the `else` clause. Nesting in the `else` clause makes each test condition of the `if` statement exclusive of the others because each test condition eliminates all the preceding conditions. Thus, in this scenario the order is important. For more information see section 4.2.2: When Order Matters.

4. Compile and run your modified program to make sure you made the changes correctly. When you run the program, the output should look like:
```Enter a score: 80
B
```

Run your program a few times with different scores to verify that any score displays the correct letter grade.

^ top

### 4.2.7: Conditional Pitfalls

• Unfortunately, you can write many things in C++ that should be incorrect but end up working for some obscure reason
• This means that you can code something that should create an error message but does not
• Thus, a program may compile and run with no error messages but still be wrong
• Since you may not realize that it is wrong, it can be hard to find and correct these types of errors

#### Using `=` Instead of `==`

• One common mistake is to use `=` when you meant to use `==`
• For example, look at the test condition in the following code:
```if (guess = 7) {
Serial.println("*** Correct! ***");
} else {
Serial.println("Sorry, that is not correct.");
}
```
• Notice that the condition is really an assignment statement and not a test
• You would think that it would fail to compile -- but it does not
• However, it will not work as you might expect
• A way to prevent this type of problem is to reverse the order of your test condition:
`if (7 = guess) {`
• Now the compiler will give you an error message and your code will not compile:
```guess.ino: In function `void loop()":
guess:10: error: non-lvalue in assignment
```
• However, if you correctly use == then your code will compile
`if (7 == guess) {`

#### Strings of Inequalities

• Do NOT use a string of inequalities like the following:
```int a = 5, b = 1, c = 10;
if (a < b < c) {
cout << "b is between a and c" << endl;
} else {
cout << "b is NOT between a and c" << endl;
}
```
• Your code may compile and run but give incorrect results
• The test condition is evaluated by the computer from left to right
• The first condition is `a < b` which evaluates to `0` (`false`)
• The second condition is then `0 < c` which evaluates to `1` (`true`)
• Since the whole test condition evaluates to `true` you get an incorrect result
• Instead, the correct way is to use `&&` as follows:
```int a = 5, b = 1, c = 10;
if (a < b && b < c) {
cout << "b is between a and c" << endl;
} else {
cout << "b is NOT between a and c" << endl;
}
```

#### Strings of Logical Operators

• Logical expressions often read like "normal" English.
• However, C++ requires more exactness than English
• For example, the following code will compile and run but give wrong results:
```int guess;
cout << "Enter a guess:" << endl;
cin >> guess;
if (guess == 7 || 8) {
cout << "*** Correct! ***" << endl;
} else {
cout << "Sorry, that is not correct." << endl;
}
```
• The test condition is evaluated by the computer from left to right
• The left hand side is (`guess == 7`) which can evaluate to either `true` or `false`
• The right hand side is `8`, which is interpreted as `true` by C++
• Since (something` or true`) is always `true`, then the test condition always evaluates to `true`
• Instead, the correct way is to use `||` as follows:
```int guess;
cout << "Enter a guess:" << endl;
cin >> guess;if (guess == 7 || guess == 8) {
cout << "*** Correct! ***" << endl;
} else {
cout << "Sorry, that is not correct." << endl;
}
```

#### Check Yourself

1. Can you spot the error in the following code fragment?
```if (person = terrorist) {
punish_severely();
} else {
return 0;
}
```

Answer and credit for the idea.

2. What is wrong with the following string of inequalities and how do you correct the code?
```int a = 5, b = 1, c = 10;
if (a < b < c) {
Serial.println("b is between a and c");
} else {
Serial.println("b is NOT between a and c");
}
```
3. What is wrong with the following string of logical operators and how do you correct the code?
```int guess;
Serial.println("Enter a guess:");guess = Serial.parseInt();
if (guess == 7 || 8) {
Serial.println("*** Correct! ***");
} else {
Serial.println("Sorry, that is not correct.");
}
```

^ top

### Summary

• By using collections of if-else statements, a program can distinguish between multiple alternatives
• Sometimes the order of statements is important for our program to work correctly
• We must think carefully and test our conditions rigorously
• Nested `if-else` statements can be used when there are two (or more) levels of decision making.
• We looked at an example of tax tables, filing as single or married
• To create conditions with multiple cases, we looked at using logical operators: `&&``||` and `!`
• We looked at some examples including:
```((guess != GUESS1) && (guess != GUESS2))
((GUESS1 == guess) || (GUESS2 == guess))
!((GUESS1 == guess) || (GUESS2 == guess))
```
• Unfortunately, you can write things in C++ that should be incorrect but end up working for some obscure reason
• These types of errors are often very difficult to find
• One common mistake is to use `=` when you mean to use `==`
`if (guess = 7)`
• Which should be written as:
`if (guess == 7)`
• Another common problem is trying to use a string of inequalities without a logical operator separating each condition, like:
`if (a < b < c)`
• Which should be written as:
`if (a < b && b < c)`
• Another common error is trying to use logical operators without enough operands:
`if (guess == 7 || 8)`
• Which should be written as:
`if (guess == 7 || guess == 8)`

#### Check Yourself

1. True or false? An elegant way to choose among multiple alternatives is to nest `if` statements in an `else` clause. (4.2.1)
2. If `score = 85`, what is output by the following code fragment? (4.2.1)
3. True or false? Order never matters in a sequence of `if` and `else` statements. (4.2.2)
4. In a game program, the scores of player A and B are stored in variables `scoreA` and `scoreB`. Assuming that the player with a larger score wins, write a sequence of conditional statements that prints our "A won", "B won" or "Game tied". (4.2.2)
5. What is the difference between if-else if-else and nested if statements? (4.2.2 vs. 4.2.4, answer)
6. True or false? A switch statement is a more powerful solution to multiple if-else if-else statements (4.2.3)
7. True or false? You can nest if statements within another if statement. (4.2.4)
8. What date type stores only the values `true` or `false`? (4.2.5)
9. When does an AND (`&&`) of two or more conditions evaluate to `true`? (4.2.6)
10. When does an OR (`||`) of two or more conditions evaluate to `false`? (4.2.6)
11. What is the effect of the NOT (`!`) operator? (4.2.5)
12. True or false? A && B is the same as B && A for any Boolean conditions A and B. (4.2.6)
13. If `score = 85`, what is output by the following code fragment? (4.2.6)
14. How many errors can you spot in the following code fragment? (4.2.7)
```if (person = terrorist) {
punish_severely();
} else {
return 0;
}
```

15. What is wrong with the following string of inequalities and how do you correct the code? (4.2.7)
```int a = 5, b = 1, c = 10;
if (a < b < c) {
Serial.println("b is between a and c");
} else {
Serial.println("b is NOT between a and c";
}
```
16. What is wrong with the following string of logical operators and how do you correct the code? (4.2.7)
```int guess;
Serial.println("Enter a guess:");
guess = Serial.parseInt();
if (guess == 7 || 8) {
cout << "*** Correct! ***\n";
} else {
cout << "Sorry, that is not correct.\n";
}```

Source: www.arduino.cc

^ top

## Wrap Up and Reminders

• For the next homework, see the schedule