4: Numbers, Conditions and Loops

What We Will Cover


Continuations

Questions from last class?

  1. For the following code, what is the value of x?
    char x = 'd' - 'a' + 'A';
    cout << x << endl;
    
  2. What is displayed by the following code?
    string str = "abc";
    str = str + "123";
    cout << str.substr(str.length() - 1, 1) << endl;
    
  3. After the following code executes, what is the value of x?
    int x = 40;
    if (x < 10)
    {
        x = x - 10;
    }
    else
    {
        x = x + 2;
    }
    

Homework Questions?

4.1: More About Variables and Numbers

Learner Outcomes

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

  • Describe exponential (scientific) notation
  • Format numbers during output
  • Discuss the reasons to use named constants instead of numbers
  • Rewrite assignment statements into shortcut alternatives
  • Generate code to convert data from one type to another
  • Diagnose problems with arithmetic precision and range and formulate solutions

4.1.1: Numbers and Arithmetic

  • Recall that C++ uses the following operators for arithmetic:
    • + for addition
    • - for subtraction
    • * for multiplication
    • / for division
    • % for modulus (remainder)
  • The dash is also used for negation (minus sign)
  • We write arithmetic expressions using combinations of numbers, variables and operators, like:
    double area = 0.0, radius = 4.3;
    area = 3.14159 * radius * radius;
    
  • As in algebra, multiplication and division are performed before addition and subtraction
  • To change the order of operation, we use parenthesis
  • Recall that the results of integer division are truncated
    7 / 2       // 3
  • We must use modulus operator (%) to get the remainder value
    7 % 2       // 1 (remainder)
  • For more complex operations we use mathematical functions from libraries such as cmath
    cout << sqrt(3.0 * 3) << endl;
  • C++ processes arithmetic expressions in the same order (precedence) as algebra:
    1. Parenthesis: ( )
    2. Function calls
    3. Unary operators: +, -
    4. Multiplication, division, modulus: *, /, %
    5. Addition, subtraction: +, -
  • Since parenthesis are processed first, we use parenthesis to change the order of operations
  • Now that we understand the basics of C++ arithmetic, we need to explore some additional features, limitations and quirks
  • We explore these items in the next sections

Check Yourself

  1. The first operation performed in the following arithmetic expression is ________.
    1 + 2 - 3 / 4 % 5 * 6
    
  2. The result of calculating 3 / 4 is ________.
  3. Write the code to calculate the square root of the number 36.

    answer

4.1.2: Exponential Notation

  • Floating-point numbers can be written in exponential notation, also known as scientific notation
  • In exponential notation, we express repeated multiplication using an exponent
  • For example, we write 10 • 10 • 10 as 103, which is a more compact form
  • The number being multiplied is the base and the power the base is being raised to is the exponent

    base   103   ← exponent

  • 103 is read as "10 to the third power" or "10 cubed" and means 10 • 10 • 10, or 1,000.
  • Exponential notations lets us express both very large and very small values in a compact form

Converting from and to Exponential Notation

  • We can easily convert a number in exponential form to standard form by moving the decimal place
  • A positive power of 10 moves the decimal point to the right
  • For example, the number 1.234 x 103 can be returned to standard form by moving the decimal 3 places to the right:
    1.234 x 103 1234
  • A negative power of 10 moves the decimal point to the left
  • Thus, we can convert 1.234 x 10-3 to standard form by moving the decimal place 3 places to the left:
    1.234 x 10-3 0.001234
  • We can convert to exponential notation by reversing the process

Examples of Exponential Notation

Decimal Form Exponential Form C++ Form
1234 1.234 x 103 1.234e3
98765 9.8765 x 104 9.87654e4
0.0123 1.23 x 10-2 1.23e-2
0.000625 6.25 x 10-4 6.25e-4

Exponential Notation in C++

  • Notice that in C++ we represent the x10 part as e or E
  • We cannot easily express an exponent in source code with standard math notation
  • Instead we substitute E for "times ten raised to the power" like: 1.234 x 103 1.234E3
  • The letter e stands for exponent
  • The number following the e is the power of 10 to multiply the first number by
  • Thus, "e" means "times ten raised to the power"

Activity: Exponential Notation

  1. Take out a piece of paper and put your name on it.
  2. Express the following quantities in C++ exponential notation: (3m)
    1. The population of the world is about 7,306,000,000. (source: census.gov)
    2. The distance from Earth to the Sun is about 92,960,000 miles.
    3. The human body contains approximately 60,000,000,000,000 to 90,000,000,000,000 cells.
    4. The mass of a particle of dust is about 0.0000000266 ounces.
    5. The length of the shortest wavelength of visible light (violet) is 0.0000004 meters.
  3. When finished, verify your exponential notation numbers with another classmate. (1m)

How Large is 1.7E308?

  • The largest possible double number is 17 followed by 307 zeros
  • How large is that?
  • The current estimate of the number of atoms in the universe is between 1.0e79 to 1.0e81
  • Mathematicians use the term "googol" for a very large number: 1.0e100
  • Data type double easily encompasses these numbers
  • What large number cannot be represented by type double?

Check Yourself

  1. True or false: one advantage of exponential notation is that you can compactly write very large and very small numbers.
  2. Write the number one billion (1,000,000,000) in exponential notation.

    answer

  3. Write the number one millionth (0.000001) in exponential notation.

    answer

More Information

4.1.3: Decimal Formatting

  • Sometimes programs may not display numbers as we would expect!
  • Consider the following program and what it will display:
    #include<iostream>
    using namespace std;
    
    int main() {
        double price = 78.50;
        cout << "The price is $" << price << endl;
    }
    
  • We must explicitly tell C++ how to output numbers in our programs
  • These commands do not produce any output directly but change how cout outputs floating-point numbers
  • "Magic Formula" to force decimal places:
    cout << fixed             // fixed notation, not scientific
         << setprecision(2);  // show 2 decimal places
    
  • The commands fixed and setprecision are known as manipulators because you can manually change how cout works
  • We can put all the commands on one line:
    cout << fixed << setprecision(2);
  • Also, we can combine the commands with other output:
    cout << "The price is $"
         << fixed << setprecision(2)
         << price << endl;
    
  • To use setprecision(), we must include the iomanip library:
    #include <iomanip>
    
  • Once we set the decimal formatting, it stays set
  • To restore the default formatting we use:
    cout << defaultfloat << setprecision(6); // 6 is default
    

Check Yourself

  1. The number 1.23 x 1012 is usually formatted by cout as ________.
  2. Rewrite the number 1.23 x 1012 in "normal" fixed notation.

    answer

  3. Write the code to display 1.23 x 1012 in "normal" fixed notation.

    answer

  4. Write the code to display $19.90.

    answer

More Information

4.1.4: Constants and Magic Numbers

  • Remember that we store data in a computers memory using variables
  • When we declare a variable, we are setting aside space in the computer's memory and giving the location a name
    int a;
    
  • To save a value in that location, we use an assignment operator (=)
    a = 1;
    
  • The above operation saves the value 1 in the memory location a
  • We can declare a variable and assign it a value in one statement like:
    int b = a;
    
  • The above statement creates a new memory location and saves the value of a in that new location

    value 2 in box bvalue 2 in box a

Constant Variables

  • A constant variable (or constant) is a variable that cannot change after being assigned a value
  • Constant variable seems oxymoronic, but is actually quite useful
  • To declare a constant, we use the keyword: const
    const int MY_CONST = 1;
    
  • We must assign a value when the constant is declared
  • If we tried to assign a value in a later statement, we get a compile-time error
  • Notice that the name is all uppercase letters with an underscore separator
  • The all uppercase convention identifies the variables as constant
  • This is a common coding convention that professional programmers follow

Magic Numbers

  • Imagine that we are hired to modify a payroll program
  • We come across the following section of code:
    int hours = 45;
    double pay;
    pay = hours * 10 + (hours / 40)
          * (hours - 40) * 10 * 0.5;
    
  • The numbers are important to the program, but what do they mean?
  • Numbers like these are called "magic numbers"
  • They are magic because their value is unexplained but necessary
    • Often, no one knows what they mean after 3 months, including the author
  • We can often deduce the meaning of numbers after reading the code carefully, which is time consuming
  • A much better coding style is to use named constants rather than literal numbers
  • For example:
    const double WAGE = 10;
    const double OVERTIME_BONUS = 0.5;
    const int HOURS_PER_WEEK = 40;
    double pay;
    pay = hours * WAGE + (hours / HOURS_PER_WEEK)
          * (hours - HOURS_PER_WEEK) * WAGE * OVERTIME_BONUS;
    
  • Now it is much easier to understand the code and see any problems or limitations
  • Another reason to use named constants is that it is easier to change the code when the number changes
  • In the above example, we can easily change WAGE without making errors in other parts of our code

Programming Style: Constant Variables and Magic Numbers

  • Since the meaning of literal ("magic") numbers is hard to remember, we should declare constants instead:
    const int FEET_PER_YARD = 3;
    const double PI = 3.14159265358979323846;
    const double WAGE = 7.5;
    const double OVERTIME_ADDER = 0.5;
    const int HOURS_PER_WEEK = 40;
    
  • Note that the name is all uppercase letters with an underscore word-separator
  • This is a common coding convention that you must follow for your constants

More Information

Activity: Name that Constant! (2m)

On your paper from the last activity, declare a constant variable for each number.

Check Yourself

  1. A numeric literal that is not assigned to a constant is known as a ________ number.
  2. Rather than use a "magic" number, instead always use a named ________.
  3. Write the code to declare a constant double named BIG_NUM and assign it a value of 100,000.

    answer

4.1.5: Assignment Operators

  • As we discussed before, we assign values to variables using an equal (=) sign
    int sum = 0;
  • The "equal sign" is really an assignment operator in C++ and does not denote equality
  • Thus, unlike math, we can have the same variable on both sides of an equals sign:
    int sum = 25;    // initialize sum to 25
    sum = sum + 10;  // add to sum
    
  • In the first line we store the value 25 in the variable sum
  • On the second line we read the value 25 from the variable sum and add 10
  • Adding two values does not change the value of the variable
  • Instead we must assign the new value (35) to the variable using the assignment operator (=)
  • Values placed into a variable replace (overwrite) previous values:

    Assigning a value to a variable

Compound Assignment Operators

  • C++ has additional assignment operators that combine other operators with assignment
    • Known as compound assignment operators
  • The general syntax is:
    variable op= expression;
  • Where op is an operator like one of the five arithmetic operators: +, -, *, /, %
  • For example, the following two statements create the same result:
    x = x + 3;
    x += 3;
    
  • Shown below are some assignment operators with examples of how they are used

Summary of Assignment Operators Used in Arithmetic Operations

Operator Description Example Equivalent To
= Assigns the value of the expression on the right to the variable on the left x = 3  
+= Adds the expression on the right to the variable on the left x += 3 x = x + 3
-= Subtracts the expression on the right from the variable on the left x -= 3 x = x - 3
*= Multiplies the expression on the right to the variable on the left and saves the result in the variable on the left x *= 3 x = x * 3
/= Divides the variable on the left by the expression on the right and saves the result in the variable on the left x /= 3 x = x / 3
%= Calculates the remainder from dividing variable on the left by the expression on the right and saves the result in the variable on the left x %= 3 x = x % 3

Increment and Decrement Operators

  • Adding or subtracting one is a common operation in programming
  • C++ provides arithmetic shortcuts for these operations with the increment and decrement operators
  • The increment operator (++) adds 1 to a variable's value
  • Preincrement adds 1 before evaluating an expression
    ++sum;
  • Post-increment evaluates the expression and then adds 1
    sum++;
  • The decrement operator works like the increments operator, except it subtracts 1 from the variable:
    --sum
    sum--
    

When Pre- and Post- Increment Matters (Optional)

  • Pre- and post- increment matters when the operation is part of a larger expression
  • For example, consider the code:
    int x = 5;
    int y = x++;
    cout << "x=" << x << " y=" << y << endl;
    
  • We may expect y to be 6 after this code executes
  • Instead, y has the value of 5
  • The reason is that ++ after a variable (post-increment) is equivalent to:
    y = x;
    x = x + 1;
    
  • On the other hand, ++ before a variable (pre-increment) is equivalent to:
    x = x + 1;
    y = x;
    

Activity: Add One (1m)

On your paper from the last activity, list all the ways to add the integer 1 to a variable named c.

Check Yourself

  1. The value of count after the following code executes is ________.
    int count = 0;
    count = count + 1;
    
  2. What is an equivalent statement for each of the following shortcut assignments?
    1. a += b;(answer)
    2. a -= b;(answer)
    3. a *= b;(answer)
    4. a /= b;(answer)
    5. a %= b;(answer)
  3. List four ways to add the integer 1 to a variable named c.

4.1.6: Type Casting

Cast: change the data type of a value in an expression

  • Recall that different data types are stored in different forms
  • Sometimes we need to change from one form to another
  • For example, arithmetic adding a double and an int value
  • C++ will automatically cast one value to another
    • Known as implicit casting or "type coercion"
  • Programmers can also explicitly cast data types using a cast operator
    (dataType) variableName
    
  • For example:
    double a = 2.99999;
    double b = (int) a;
    cout << a << " " << b << endl;
    
  • The value of a is converted from type double to int before assigning the converted value to b
  • However, a remains a type double and the cast only applies to a single use of a
  • The above example shows a common use of casting -- removing the decimal part of a floating-point number
  • Note that the decimal portion of the number is truncated and NOT rounded
  • The decimal part is lost (discarded, ignored, thrown away)

Other Uses for Casting

  • Consider the following code:
    int degF = 70;
    int degC =  5 / 9 * (degF - 32);
    cout << degF << "F is " << degC << "C" << endl;
    
  • What is the problem with the above code?
  • To correct the problem we can use a cast, like:
    int degF = 70;
    int degC =  (double) 5 / 9 * (degF - 32);
    cout << degF << "F is " << degC << "C" << endl;
    
  • The value 5 is converted from type int to double before the integer division
  • Still another use for casting is to convert a number to a character
    int x = 65;
    cout << x << (char) x << endl;
    

New Style Casting

  • C++ has many styles of casting
  • The newer style of casting is of the form:
    static_cast<toType>(expression)
  • For example:
    double a = 2.99999;
    double b = static_cast<int>(a);
    cout << a << " " << b << endl;
    

Example Application Using Casting: cast.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
using namespace std;

int main() {
    double input;
    cout << "Enter hours: ";
    cin >> input;

    int hours = input;
    int minutes = ((input - (int) input) * 60);
    cout << "In hours and minutes, this is "
         << hours << ":" << minutes << endl;
    return 0;
}

Check Yourself

  1. True or false: the reason for using a typecast is to temporarily convert the type of a value.
  2. Of the following, ________ is a valid typecast.
    1. a (int)
    2. int:a;
    3. (int) a;
    4. to(int, a);
  3. True or false: type casting permanently changes the type of a variable.
  4. Enter the code to truncate the decimal part of double variable named x.

    answer

Exercise 4.1: Exploring Numeric Features of C++ (10m)

In this exercise we explore some additional numeric features of C++.

Specifications

  1. Copy the following program into a text editor and save it as prod.cpp:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    
    #include <iostream>
    #include <iomanip>
    using namespace std;
    
    int main() {
        string name;
        double price = 0;
    
        cout << "Enter the product name: ";
        cin >> name;
        cout << "Price of the " << name << ": ";
        cin >> price;
    
        // Insert new statements here
    
        cout << "Total price: $" << price << endl;
    
        return 0;
    }
    
  2. Compile and run the starter program to make sure you entered it correctly.

    When you run the program, the output should look like this:

    Enter the product name: iPod_Nano
    Price of the iPod_Nano: 149.50
    Total price: $149.5
    

    Note the format of the numbers output for the total price. We will address this formatting issue later in the exercise.

  3. Run the program again for a product with a very high cost, like a Boeing 777:
    Enter the product name: Boeing__777
    Price of the Boeing_777: 277345678
    Total price: $2.77346e+08
    

    Note the format of the numbers output for the total price. This format is called exponential notation. For more information on exponential notation, see section: 4.1.2: Exponential Notation.

  4. Let us correct the formatting of the total price. Enter the following code before the statement that prints the total price:
    cout << fixed             // fixed notation, not scientific
         << setprecision(2);  // show 2 decimal places
    

    These statements are referred to as the "magic formula" because they for C++ to output statements in a "standard" format. Note what each statement accomplishes. For more information, see section: 4.1.3: Decimal Formatting.

  5. Compile and run your program again and verify the output looks like:
    Enter the product name: Boeing_777
    Price of the Boeing__777: 277345678
    Total price: $277345678.00
    
  6. Let us add a constant that we will use later in our program. Enter the following code after the magic formula and before the statement that prints the total price:
    const int PERCENT = 100;
    

    A constant variable (or constant) is a variable that cannot change after being assigned a value. Using a constant lets us avoid using a vague number. For more information, see section: 4.1.4: Constants and Magic Numbers.

  7. Now we will add sales tax to the price of the product. Enter the following code after the constant and before the statement that prints the total price:
    double taxRate = 0;
    cout << "Enter sales tax rate (%): ";
    cin >> taxRate;
    double tax = price * taxRate / PERCENT;
    price += tax;
    

    Notice the last statement: price += tax;. This is an alternate way to code the statement: price = price + tax;. For more information, see section: 4.1.5: Assignment Operators.

  8. Compile and run your modified program and verify the output looks like:
    Enter the product name: iPod_nano
    Price of the iPod_nano: 149.50
    Enter sales tax rate (%): 9.5
    Total price: $163.70
    
  9. Now we will find the whole dollars and cents of the amount to demonstrate casting. Enter the following code after the statement that prints the total price and before the return statement:
    int dollars = (int) price;
    cout << "In whole dollars: $" << dollars << endl;
    

    Notice the (int) in the first statement. This is known as a type cast or just cast. For more information, see section: 4.1.6: Type Casting.

  10. Compile and run your modified program and verify the output looks like:
    Enter the product name: iPod_nano
    Price of the iPod_nano: 149.50
    Enter sales tax rate (%): 9.5
    Total price: $163.70
    In whole dollars: $163
    
  11. Submit your program source code to Canvas as part of assignment 4.
  12. Also, work through the examples in section: 4.1.7: Arithmetic Precision and Range.

When finished, please help those around you.

Completed Program

Once you are finished, your source code should look like the following (excluding comments):

Listing of price.cpp

4.1.7: Numeric Precision and Range

  • An integer is stored in a computer as a pure binary number:
integer representation
Image source: Dan Gookin
  • The sign bit sets whether the number is positive (0) or negative (1)
  • The other bits represent the value, in this case 123
  • There are only a finite set of numbers in an integer value
  • What happens when an integer is too big for its type?
    int bigPlus = 2147483647;
    cout << "Big number: ";
    cout << bigPlus + 1 << endl;
    int bigMinus = -2147483647;
    cout << "Small number: ";
    cout << bigMinus - 2 << endl;
    
  • The number "wraps around" from the highest number to the lowest
  • You must be careful that your program will not go beyond the range of its data types
  • Can't sleep: from xkcd

More Integer Types

  • The int data type contains at least 16 bits
  • C++ also has the long data type with at least 32 bits
  • With the development of 32 bit computers, the int type was usually implemented as 32 bits, the same as long
  • To address the problem, C++11 added the long long data type containing at least 64 bits
    long long int x = -9223372036854775807; // about -9.22 x10^18
    cout << x << endl;
    
  • As with the int and long tyes, C++ has unsigned modifier
    unsigned long long int y = x * -2; // about 1.8 x10^19
    cout << y << endl;
    

Floating-Point Precision and Range

  • Real numbers, which include decimal points, cannot all be represented on a binary computer directly
  • Instead, the computer must approximate the numbers using floating point format
  • For example, a floating-point value of 13.5 would look like this as a float data type:
single precision representation
Image source: Dan Gookin
  • The sign bit works the same as for integer numbers
  • The rest of the number is divided between the exponent and mantissa
  • The mantissa is multiplied by the base (2) to the exponent to give the actual value of the number

    Mantissa * 2 Exponent

  • Notice that in a float (4 bytes) the number of bits for the mantissa is less than for an int
  • The limited mantissa can lead to rounding errors occur in repeated calculations
  • Type double has about twice the precision of type float
  • However, even type double can have rounding errors
    cout << setprecision(50);
    cout << .8F + .1F << endl;
    cout << .8 + .1 << endl;
    cout << 4.35 << endl;
    
  • When floating point numbers get too large, they are set to inf
  • For example:
    cout << 2E38F + 2E38F << endl;
    cout << 1.7E308 + 1.7E308 << endl;
    
  • Similarly, when numbers are too small they are set to 0.0

The Moral

  • Integer numbers are exact (not approximated in any way) but limited in their range
  • If we work with large integers, we must be sure we to not exceed the range of the data type
  • Floating-point numbers have more range but limited precision
  • When math operations are performed repeatedly, floating-point numbers can become less accurate
  • Thus we must be careful of precision when using floating-point numbers

Check Yourself

  1. True or false: when you increase the value of a signed integer beyond its range, it rolls over to a negative number.
  2. Approximately ________ digits can be accurately stored in a type float and ________ in type double.
  3. The output of the following code fragment is ________. Why? (answer)
    cout << setprecision(17);
    double r = sqrt(2);
    if (r * r == 2) {
        cout << "sqrt(2) squared is 2\n";
    } else {
        cout << "sqrt(2) squared is not 2 but "
             << (r * r) << endl;
    }
    
  4. What is the difference between exact and precise?
  5. True or false: an int is more exact than a double.

4.1.8: Summary

  • In this section we discussed more details about programming with variables and numbers
  • Constants are a variable that cannot change after it is first assigned a value
  • To declare a constant, we use the keyword: const
    const int MY_CONST = 1;
  • Constants are used to apply meaningful names to numbers
  • Another reason to use named constants is that it is easier to change the value of the number
  • To save typing, C++ has assignment variations of the form:
    variable <op>= expression;
  • For example, the following statements create the same result:
    c = c + 1;
    c += 1;
    c++;
    
  • C++ will automatically cast data of one type to another when necessary
  • However, you can explicitly cast values to a different type.
  • We must explicitly cast when C++ does not perform as you want.
  • For example:
    double x = (double) 9 / 5;
    cout << x << endl;
    
  • When floating-point numbers get very large or very small, C++ displays them using exponential (scientific) notation
  • cout includes special functions to specify the output of type double
  • The following "magic formula" lets us display numbers with 2 decimal places:
    cout << fixed             // fixed notation, not scientific
         << setprecision(2);  // show 2 decimal places
    
  • Not all numbers can be represented accurately by primitive C++ types
  • Integer values have a limited range
  • If your program assigns values too high or too low, integers wrap around
    int bigPlus = 2147483647;
    cout << "Big number: ";
    cout << bigPlus + 1 << endl;
    int bigMinus = -2147483647;
    cout << "Small number: ";
    cout << bigMinus - 2 << endl;
    
  • Floating-point numbers usually have enough range
  • However, they often suffer from lack of precision
    cout.precision(50);
    cout << .8F + .1F << endl;
    cout << .8 + .1 << endl;
    cout << 4.35 << endl;
    
  • Type double has about twice the precision of type float
  • When floating point numbers get too large, they are set to inf
  • Similarly, when too small they are set to 0.0

Check Yourself

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

  1. How are very large or very small numbers floating point numbers formatted by default when displayed with cout? (4.1.5)
  2. What is the "magic formula" for displaying numbers in decimal notation? (4.1.6)
  3. What is the purpose of each line of the magic formula? (4.1.6)
  4. What is the code to declare a constant double named BIG_NUM and assign it a value of 100,000? (4.1.1)
  5. What is an equivalent statement for each of the following shortcut assignments? (4.1.2)
    1. a += b;
    2. a -= b;
    3. a *= b;
    4. a /= b;
    5. a %= b;
  6. How many ways can you add the integer 1 to a variable named index? List each way. (4.1.2)
  7. Which is a valid typecast? (4.1.3)
    1. a(int)
    2. int:a;
    3. (int)a;
    4. to(int, a);
  8. How can you truncate the decimal part of double variable? (4.1.3)
  9. What happens when you increase the value of a signed integer beyond its range? (4.1.7)
  10. How many digits that can be accurately stored in a type float? double? (4.1.7)
  11. What is the output of the following code fragment? Why? (4.1.7)
    cout.precision(17);
    double r = sqrt(2);
    if (r * r == 2) {
        cout << "sqrt(2) squared is 2\n";
    } else {
        cout << "sqrt(2) squared is not 2 but "
             << (r * r) << endl;
    }
    

4.2: More About Selections

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

4.2.1: Reviewing Selection Statements

  • By default, code executes sequentially: one statement after another from top to bottom within a function like main()
  • Sometimes we want to change this sequential flow
  • One way to change the flow is a selection statement, also known as a conditional statement or if-statement
  • A selection statement contains code that executes if and only if a test condition evaluates to true
  • An if statement has two parts: a test and a body
    if (test) {
       body with statements to execute
    }
    
  • For example, in the following the message is displayed if and only if the value of guess equals 7:
    if (7 == guess) {
      cout << "*** Correct! ***\n";
    }
    
  • The message does NOT display if the test condition evaluates to false
  • Adding an else-clause causes statements to execute when a test condition evaluates to false:
    if (7 == guess) {
        cout << "*** Correct! ***\n";
    } else {
        cout << "Sorry, that is not correct.\n";
    }
    

Relational Operators

  • Relational operators are a common way to create a test condition
  • Relational operators include:
    ==  !=  <   <=  >   >=
  • Relational operators can be used with numbers, characters and strings
  • However, both operands must be compatible types

relational expression

Nesting

  • We can nest if statements within other if statements
  • The inner if statement is evaluated only if the test condition of the outer if test first evaluates to true
    if (guess != 7) {
        if (guess < 7) {
            cout << "Your guess is too low.\n";
        } else {
            cout << "Your guess is too high.\n";
        }
    } else {
        cout << "*** Correct! ***\n";
    }
    
  • Nesting allows us to test to test multiple conditions and select from multiple alternatives
  • We can nest if-statements in either the if-clause or the else-clause
  • When nested in the else-clause, a program makes only one selection among all the alternatives
  • As soon as a condition evaluates to true, the rest of the selections are ignored
  • Because of these properties, if-else-if statements are usually formatted as follows:
    if (guess < 7) {
        cout << "Your guess is too low.\n";
    } else if (guess > 7) {
        cout << "Your guess is too high.\n";
    } else {
        cout << "*** Correct! ***\n";
    }
    
  • This formatting more clearly shows the sequence of tests, which are:
    • The computer starts at the top
    • The computer makes only one selection
    • Once the selection is made and processes, the computer skips the rest of the options
  • The formatting also prevents indentations creeping to the right as more selects are added

Check Yourself

  1. True or false: the default behavior for a computer program is to execute statements sequentially.
  2. What is the value of x after the following code segment? (answer)
    int x = 5;
    if (x > 3)
    {
        x = x - 2;
    }
    else
    {
        x = x + 2;
    }
    
  3. The following code displays ________.
    int guess = 8;
    if (guess < 7)
    {
        cout << "Your guess is too low.\n";
    }
    else if (guess > 7)
    {
        cout << "Your guess is too high.\n";
    }
    else
    {
        cout << "*** Correct! ***\n";
    }
    

4.2.2: Multiple Alternatives

  • By using collections of if-else statements, a program can distinguish between multiple alternatives
  • For example, consider the following example where a user enters the name of a coin, and the program displays the value

Program Converting Coin Names to Values

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
using namespace std;

int main() {
    cout << "Enter coin name: ";
    string name;
    cin >> name;
    double value = 0;

    if (name == "penny") {
        value = 0.01;
    } else if (name == "nickel") {
        value = 0.05;
    } else if (name == "dime") {
        value = 0.10;
    } else if (name == "quarter") {
      value = 0.25;
    } else {
        cout << name << " is not a valid coin name\n";
    }
    cout << "Value = " << value << "\n";

    return 0;
}

Flowchart of multiple alternatives

Choosing Between Alternatives

  • This program has five alternatives to choose from:
    1. "penny"
    2. "nickel"
    3. "dime"
    4. "quarter"
    5. error message
  • Note that the order that the alternatives are checked is unimportant
  • We can follow the alternatives in the flowchart shown below

Check Yourself

  1. In the above program, what happens if the user enters the word, "dollar"?
  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?

    if-else statements

  4. In the above sequence of if-statements, the test condition of the first if-statement must be ________ before the second if-statement executes.

4.2.3: When Order Matters

  • In some cases, the order of the tests is important
  • For example, look at the following program from the textbook that displays a description of the likely impact of an earthquake based on its magnitude on the Richter scale

Program Showing Multiple Alternatives Where Order Matters

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
#include <iostream>
using namespace std;

int main() {
    cout << "Enter a magnitude on the Richter scale: ";
    double richter;
    cin >> richter;

    if (richter >= 8.0) {
        cout << "Most structures fall\n";
    } else if (richter >= 7.0) {
        cout << "Many buildings destroyed\n";
    } else if (richter >= 6.0) {
        cout << "Many buildings considerably damaged, "
             << "some collapse\n";
    } else if (richter >= 4.5) {
        cout << "Damage to poorly constructed buildings\n";
    } else if (richter >= 3.5) {
        cout << "Felt by many people, no destruction\n";
    } else if (richter >= 0) {
        cout << "Generally not felt by people\n";
    } else {
        cout << "Negative numbers are not valid\n";
    }

    return 0;
}

Order Is Important

  • Note that the order of the tests is important to ensure that the right results are printed
  • 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 (richter >= 0) { // tests in wrong order
        cout << "Generally not felt by people\n";
    } else if (richter >= 3.5) {
        cout << "Felt by many people, no destruction\n";
    } else if (richter >= 4.5) {
        cout << "Damage to poorly constructed buildings\n";
    } else if (richter >= 6.0) {
        cout << "Many buildings considerably damaged, "
             << "some collapse\n";
    } else if (richter >= 7.0) {
        cout << "Many buildings destroyed\n";
    } else if (richter >= 8.0) {
        cout << "Most structures fall\n";
    } else {
        cout << "Negative numbers are not valid\n";
    }
    
  • This does not work because all values meet the first condition
  • Every other test 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 (richter >= 8.0) { // Does not use else
        cout << "Most structures fall\n";
    }
    if (richter >= 7.0) {
        cout << "Many buildings destroyed\n";
    }
    if (richter >= 6.0) {
        cout << "Many buildings considerably damaged, "
             << "some collapse\n";
    }
    if (richter >= 4.5) {
        cout << "Damage to poorly constructed buildings\n";
    }
    if (richter >= 3.5) {
        cout << "Felt by many people, no destruction\n";
    }
    if (richter >= 0) {
        cout << "Generally not felt by people\n";
    }
    if (richter < 0) {
        cout << "Negative numbers are not valid\n";
    }
    
  • 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 someone entered -1 into the Richter 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;
    }
    

Exercise 4.2a: Multiple Alternatives (5m)

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.

Numerical Grade Letter Grade
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

Remember to verify your code by compiling after each step.

Specifications

  1. Copy the following program into a text editor, save it as grader.cpp, and then compile and run the starter program to make sure you copied it correctly.
    #include <iostream>
    using namespace std;
    
    int main() {
        // Enter your code here
    
        return 0;
    }
    
  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. Add the series of if statements shown below into grader.cpp as shown below:

    if-else statements

    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.3: 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.

  5. Submit your final program source code to Canvas as part of assignment 4.

As time permits, please help those around you.

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

Flowchart of nested branches

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
#include <iostream>
using namespace std;

int main() {
    const double SINGLE_LOW = 21450.00;
    const double SINGLE_MID = 51900.00;
    const double SINGLE_TAX1 = 3217.50;
    const double SINGLE_TAX2 = 11743.50;

    const double MARRIED_LOW = 35800.00;
    const double MARRIED_MID = 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;

    cout << "Enter marital status (s=single, m=married): ";
    string maritalStatus;
    cin >> maritalStatus;

    cout << "Enter your income: ";
    double income;
    cin >> income;

    double tax;
    if (maritalStatus == "m") {
        if (income <= MARRIED_LOW) {
            tax =  RATE1 * income;
        } else if (income <= MARRIED_MID) {
            tax = MARRIED_TAX1 + RATE2 * (income - MARRIED_LOW);
        } else {
            tax = MARRIED_TAX2 + RATE3 * (income - MARRIED_MID);
        }
    } else {
        if (income <= SINGLE_LOW) {
            tax =  RATE1 * income;
        } else if (income <= SINGLE_MID) {
            tax = SINGLE_TAX1 + RATE2 * (income - SINGLE_LOW);
        } else {
            tax = SINGLE_TAX2 + RATE3 * (income - SINGLE_MID);
        }
    }
    cout << "The tax is $" << tax << "\n";

    return 0;
}

Avoiding Magic Numbers

  • We should avoid magic numbers by using named constants like the ones shown above
  • Using named constants clarify the formulas and make updates easier

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

Exercise 4.2b: Multi-Level Decisions (7m)

In this exercise we program multiple levels of decisions into a program. As an example, we will calculate an insurance premium according to the following table. As usual, verify your code by compiling after each step.

Marital Status Age Premium
Single Under 21 1500
Single 21 to 29 1200
Single Over 29 1000
Married Under 21 1200
Married 21 to 29 1000
Married Over 29 800

Specifications

  1. Copy the following program into a text editor, save it as insurance.cpp, and then compile and run the starter program to make sure you copied it correctly.
    #include <iostream>
    using namespace std;
    
    int main() {
        // Enter your code here
    
        return 0;
    }
    
  2. Add code to read user input for the following:
    1. a variable of type string for storing an "m" or "s".
    2. a numeric variable for storing an age in years
    When you run the program after adding this code, the output should look like:
    Enter marital status (s=single, m=married): m
    Enter your age in years: 42
    

    Make sure you declare the variables 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.2.3: Input and Output.

  3. After the user input, declare a variable to store insurance premium amount and add an if-else statement for a decision on marital status like:
    int premium = 0;
    if (maritalStatus == "m") {
        // code if married
    } else {
        // code if single
    }
    

    For more information see section section 4.2.4.

  4. In the if-clause, add a cascading if-else structure for deciding on the insurance premiums when married like:
    if (age < 21) {
        premium = 1200;
    } else if (age <= 29) {
        premium = 1000;
    } else {
        premium = 800;
    }
    
  5. Within the else-clause of the outer if-statement, write a nested if-else-if statement to display the premiums shown in the table above for a marital status of single.
  6. Compile and run your modified program to verify you wrote it correctly. When you run the program, the output should look like:
    Enter marital status (s=single, m=married): m
    Enter your age in years: 42
    Premium is 800
    

    Run your program a few times with different scores to verify that any score displays the correct premium as shown in the table.

  7. Submit your final program source code to Canvas as part of assignment 4.

As time permits, please help those around you.

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)
  • As you can see, we can do a lot with Boolean variables

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
18
19
20
#include <iostream>
using namespace std;

// For testing
int main() {
    double num;
    cout << "Enter a number: ";
    cin >> num;

    bool isPositive = (num >= 0);
    cout << boolalpha; // output true or false for bool
    cout << "The test evaluated to: " << isPositive << endl;
    if (isPositive) {
        cout << "The number was 0 or positive\n";
    } else {
        cout << "The number was negative\n";
    }

    return 0;
}

More Information

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.

4.2.6: Logical Operators

  • Sometimes we need to test for multiple conditions in our programs
  • For example, we want to test for membership and an age >= 21
  • We need to test both for membership and age >= 21
  • One way to make the tests is with nested if-statements
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
using namespace std;

int main() {
    cout << "Are you a member? (y/n): ";
    char member = 0;
    cin >> member;

    cout << "Enter your age: ";
    int age = 0;
    cin >> age;
    if (member == 'y') {
        if (age >= 21) {
            cout << "You may enter!\n";
        } else {
            cout << "Entry denied.\n";
        }
    } else {
        cout << "Entry denied.\n";
    }

    return 0;
}
  • If both the membership and age is correct, we get the message, "You may enter!"
  • If either the membership or age entered is not correct, we get the message, "Entry denied."
  • While this approach 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

  • A logical operator, or Boolean operator, is a connective for 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 key 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

Activity: construct a truth table for

(member == 'y' and age >= 21)
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

Activity: construct a truth table for

(member == 'y' or age >= 21)
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 membership and age test using an and (&&) operator like this:
    if (member == 'y' and age >= 21)
    {
        cout << "You may enter!\n";
    }
    else
    {
        cout << "Entry denied.\n";
    }
    
  • Notice that the code is shorter and it is easier to follow the with nested if-statements
  • Another way to use logical operators to test the membership and age is:
    if (member != 'y' or age < 21) {
    {
        cout << "Entry denied.\n";
    }
    else
    {
        cout << "You may enter!\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
  • If we substitute 1 for true and 0 for false, we have these truth tables:

two value logic tables

  • With this substitution we see that the AND operation is the minimum of the operands
  • Conversely, the OR operation is the maximum of the operands
  • 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)
  • In coding, clarity is more important than brevity
  • Thus, 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
15
#include <iostream>
using namespace std;

int main()
{
    cout << "Enter two operands using 1 for true and 0 for false: ";
    bool op1 = false, op2 = false;
    cin >> op1 >> op2;
    cout << op1 << " and " << op2 << " = " << (op1 and op2) << endl;
    cout << op1 << " or " << op2 << " = " << (op1 or op2) << endl;
    cout << "Not " << op1 << " = " << (!op1) << endl;
    cout << "Not " << op2 << " = " << (!op2) << endl;

    return 0;
}

More Information

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;
    cout << (denim && lenses)
    
  5. For the following code, the test condition evaluates to ________.
    int age = 21;
    cout << (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)

Exercise 4.2c: Logical Operators (7m)

In this exercise we test multiple alternatives in a program. As an example, we will calculate a simple guide of what to eat when you are hungry depending on the temperature. Verify your code by compiling after each step, as usual.

Specifications

  1. Copy the following program into a text editor, save it as foodguide.cpp, and then compile and run the starter program to make sure you copied it correctly.
    #include <iostream>
    using namespace std;
    
    int main() {
        // Enter your code here
    
        return 0;
    }
    
  2. Add code to get user input into a variable of type int named temp. When you run the program after adding this code, the output should look like:
    Enter the temperture in degrees fahrenheit: 100
    

    Note that the underlined numbers above shows what the user enters and is not part of your code. For more information see section 2.2.3: Input and Output.

  3. Add code that asks if a user is hungry and stores the result in a variable of type char named answer.When you run the program after adding this code, the output should look like:
    Enter the temperture in degrees fahrenheit: 100
    Are you hungry (y/n): y
    
  4. After the user enters whether or not the person is hungry, convert the answer to a boolean variable named hungry using a relational expression like:
    bool hungry = (answer == 'y');
    

    For more information see section 4.2.5: Boolean Variables.

  5. Add the series of if statements shown below after the previously entered code:

    logical operators

  6. Compile and run your program to make sure you made the changes correctly. When you run the program, the output should look like:
    Enter the temperture in degrees fahrenheit: 100
    Are you hungry? y
    Eat ice cream
    

    Run your program a few times with different inputs to verify the choices make sense.

  7. Save your foodguide.cpp file to submit as part of the next assignment.

When finished please help those around you.

4.2.7: Conditional Pitfalls

  • Unfortunately, we can write many things in C++ that should be incorrect but end up working for some obscure reason
  • This means that we 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 we may not realize that the code is wrong, it can be hard to find and correct these types of errors

Using = Instead of ==

  • One common mistake is to use = when we meant to use ==
  • For example, look at the test condition in the following code:
    if (guess = 7) {
        cout << "*** Correct! ***\n";
    } else {
        cout << "Sorry, that is not correct.\n";
    }
    
  • Notice that the condition is really an assignment statement and not a test
  • We may think that it would fail to compile -- but it does not
  • However, it will not work as we might expect
  • A way to prevent this type of problem is to reverse the order of our test condition:
    if (7 = guess) {
  • Now the compiler will give us an error message and our code will not compile:
    guess.cpp: In function `int main()":
    guess.cpp:10: error: non-lvalue in assignment
    
  • However, if we correctly use == then our 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\n";
    } else {
        cout << "b is NOT between a and c\n";
    }
    
  • Our 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 we 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\n";
    } else {
        cout << "b is NOT between a and c\n";
    }
    

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: ";
    cin >> guess;
    if (guess == 7 || 8) {
        cout << "*** Correct! ***\n";
    } else {
        cout << "Sorry, that is not correct.\n";
    }
    
  • 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: ";
    cin >> guess;
    if (guess == 7 || guess == 8) {
        cout << "*** Correct! ***\n";
    } else {
        cout << "Sorry, that is not correct.\n";
    }
    

Check Yourself

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

    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) {
        cout << "b is between a and c\n";
    } else {
        cout << "b is NOT between a and c\n";
    }
    
  3. What is wrong with the following string of logical operators and how do you correct the code?
    int guess;
    cout << "Enter a guess: ";
    cin >> guess;
    if (guess == 7 || 8) {
        cout << "*** Correct! ***\n";
    } else {
        cout << "Sorry, that is not correct.\n";
    }
    

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

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

  1. True or false? An elegant way to choose among multiple alternatives is to nest if statements in an else clause. (4.2.2)
  2. If score = 85, what is output by the following code fragment? (4.2.2)

    if-else statements

  3. True or false? Order never matters in a sequence of if and else statements. (4.2.3)
  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.3)
  5. What is the difference between if-else and nested if statements? (4.2.3 vs. 4.2.4
  6. True or false? You can nest if statements within another if statement. (4.2.4)
  7. What date type stores only the values true or false? (4.2.5)
  8. When does an AND (&&) of two or more conditions evaluate to true? (4.2.6)
  9. When does an OR (||) of two or more conditions evaluate to false? (4.2.6)
  10. What is the effect of the NOT (!) operator? (4.2.5)
  11. True or false? A && B is the same as B && A for any Boolean conditions A and B. (4.2.6)
  12. If score = 85, what is output by the following code fragment? (4.2.6)

    Testing with logical operators

  13. How many errors can you spot in the following code fragment? (4.2.7)
    if (person = terrorist) {
        punish_severely();
    } else {
        exit(-1);
    }
    

    Answer and credit for the idea.

  14. 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) {
        cout << "b is between a and c\n";
    } else {
        cout << "b is NOT between a and c\n";
    }
    
  15. What is wrong with the following string of logical operators and how do you correct the code? (4.2.7)
    int guess;
    cout << "Enter a guess: ";
    cin >> guess;
    if (guess == 7 || 8) {
        cout << "*** Correct! ***\n";
    } else {
        cout << "Sorry, that is not correct.\n";
    }
    

4.3: Repetition (Loops)

Objectives

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

  • Use while statements to repeat sections of code
  • Discuss the usual parts of a loop
  • Describe what is meant by a main loop

4.3.1: Simple Loops

  • Sometimes we want to repeat a section of code
  • For instance, we may want to let a user run our program multiple times
  • When we want to repeat a section of code, we use a loop statement
  • A loop is a block of code that can execute repeatedly
  • Whether or not a program repeats a block of code is determined by a test condition
  • The test condition is checked each time through the loop

Mark Zuckerburg teaches Repeat Loops (1:31)

  • There are three general purpose loop statements in C++:
    • for
    • while
    • do...while
  • We will start with the simplest of the three -- the while statement

Check Yourself

  1. The purpose of a loop is to ________ a block of code.
  2. True or false: a test condition is checked each time a loop repeats.
  3. The three general purpose loops are: ________, ________ and ________.

4.3.2: Coding while Statements

  • The simplest looping structure is the while statement
  • A while statement has a test condition and a body, like an if statement
  • Before each execution of the loop body, the while statement checks the test condition
  • If the test condition evaluates to true, then our program executes the body of the loop
  • When the program reaches the end of the loop body, it automatically returns to the while statement
  • Syntax:
    while (test) {
       statement1
       statement2
       ...
    }
    
  • Where:
    • test: the test condition to evaluate
    • statementX: the statements to execute while the test remains true
  • For example:
    char repeat = 'y';
    while ('y' == repeat) {
        // ... statements to repeat
        cin >> repeat;
    }
    
  • The following flow chart shows how the while loop operates

Diagram of while Loop Operation

While loop syntax and flow chart

Check Yourself

  1. True or false: a while-loop includes an initialization statement as part of its syntax.
  2. A test condition must evaluate to ________ for a while loop to execute its body of statements.
  3. True or false: if the test condition of a while-loop evaluates to false, the statement after the while loop executes.

4.3.3: Understanding the while Loop

  • The following looping application simulates the play of an exciting game
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
using namespace std;

int main() {
    char repeat = 'y';
    while ('y' == repeat) {
        cout << "\nPlaying an exciting game!\n";
        cout << "Do you want to play again? (y/n) ";
        cin >> repeat;
    }
    cout << "\nThanks for playing!\n";

    return 0;
}
  • Notice the structure of the code for the looping application
  • First was the statement to correctly initialize the looping condition:
    char repeat = 'y';
    
  • Then came the while statement with the test condition
    while ('y' == repeat)
  • The loop executes the body of the loop if and only if the condition evaluates to true
  • Another important part of the loop is the statement:
    cin >> repeat;
  • Most loops have these parts:
    • Initialization code
    • Loop test condition
    • Loop body with some way to change the test condition
  • We will further explore the while loop in the next exercise

About those Curly Braces

  • Like the if-statement, the curly braces of a while loop are optional
  • Technically, the while statement affects only the single statement that follows
  • We use curly braces to make that one statement into a block of statements
  • This allows us to put any number of statements within the body
  • Curly braces are not always required, but the best practice is to always include them

Program Style: Indent Statements Inside a Loop

  • It is important to format the loop code correctly:
    char repeat = 'y';
    while ('y' == repeat) {
        // ... statements to repeat
        cin >> repeat;
    }
    
  • Note how the repeated code is indented inside the loop
  • This lets us see easily which code is repeated and which is not
  • Also note the placement of curly braces
  • Different groups have different practices for placing curly braces in a loop statement
  • For the acceptable styles for this course see: Curly Braces

Check Yourself

  1. True or false: if the test condition of a while loop evaluates to false the first time the loop is reached, it still executes one time.
  2. In the example code, which statement initializes the variable?
  3. True or false: the while-statement affects only a single statement unless curly braces are used.
  4. Which parts of a while-statement are indented?

Exercise 4.3: Repeating a Program (5m)

In this exercise we use a loop to allow a user to repeat a program.

Specifications

  1. Copy the following program into a text editor, save it as loopy.cpp, and then compile and run the starter program to make sure you copied it correctly.
    #include <iostream>
    using namespace std;
    
    
    int main() {
        int guess = 0;
        cout << "I'm thinking of a number between"
             << " 1 and 10.\nCan you guess it?\n\n"
             << "Enter your guess: ";
        cin >> guess;
    
        if (7 == guess) {
            cout << "*** Correct! ***\n";
        } else {
            cout << "Sorry, that is not correct.\n";
            cout << "Try again.\n";
        }
        return 0;
    }
    
  2. Add the following code after the statement int guess = 0; and before the cout statement:
    char repeat = 'y';
    

    This is the initialization code that we will use for the test condition that comes next.

  3. We want to repeat all the rest of the code in our program. For this we need to add a while statement such as:
    while ('y' == repeat) {
        // Place the rest of the code after the initialization
        // and before the return 0 between these curly braces.
    }
    

    Statements inside the curly braces repeat while the test condition in the parenthesis, ('y' == repeat), evaluates to true. For more information, see section: 4.3.2: Coding while Statements.

  4. Inside the while loop we need some way to change the test condition. We change the test condition by letting the user enter a value for the repeat variable by adding the following code at the end of the loop just before the closing curly brace:
    cout << "\nDo you want to play again? (y/n) ";
    cin >> repeat;
    

    Without these two statements our loop would have no way to exit. A loop with no way to exit is known as an infinite loop. For more information, see section: 4.3.3: Understanding the while Loop.

  5. Formatting a loop is important. Indent all the code within the curly braces of the while loop. For more information, see Formatting the Code in the section: 4.3.3: Understanding the while Loop.
  6. As a final part of our program, we add the infamous phrase: "Game Over". Add the following statement after the closing curly brace of the while loop:
    cout << "Game over\n";
    
  7. Compile and run your program again and verify the output looks like:
    I'm thinking of a number between 1 and 10.
    Can you guess it?
    
    Enter your guess: 3
    Sorry, that is not correct.
    Try again.
    
    Do you want to play again? (y/n) y
    I'm thinking of a number between 1 and 10.
    Can you guess it?
    
    Enter your guess: 7
    *** Correct! ***
    
    Do you want to play again? (y/n) n
    Game over
    
  8. Submit your program source code to Canvas as part of assignment 4.

Completed Program

When finished, your application should look like the following. Note especially the extra indentation within the curly braces of the while loop.

Completed exercise

As time permits, read the following sections and be prepared to answer the Check Yourself questions in the section: 4.3.5: Summary.

4.3.4: Common Loop Pitfalls

  • Loops have many pitfalls for the unwary
  • The following are the most common problems you should look out for

Infinite Loops

  • Common error: unintentional infinite loop
  • For example, what is wrong with the following code?
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
using namespace std;

int main() {
    string repeat = "y";
    while ("y" == repeat) {
        cout << "\nPlaying an exciting game!\n";
        cout << "Do you want to play again? (y/n) ";
    }
    cout << "\nThanks for playing!\n";

    return 0;
}

Missing Curly Braces

  • Technically, the while loop executes a single statement after the parenthesis of the test condition
  • However, we usually use curly braces { } to expand the single statement
  • The curly braces let us put multiple statements in them
  • For example, what is wrong with the following code?
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
using namespace std;

int main() {
    string repeat = "y";
    while ("y" == repeat)
        cout << "\nPlaying an exciting game!\n";
        cout << "Do you want to play again? (y/n) ";
        cin >> repeat;
    cout << "\nThanks for playing!\n";

    return 0;
}

Empty Statements

  • Remember that statements are terminated by a semicolon
  • Is the following a legal statement?
    ;
  • This is known as an empty or null statement
  • Empty statements are a common source of infinite loops
  • For example, what is wrong with the following code?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
using namespace std;

int main() {
    string repeat = "y";
    while ("y" == repeat); {
        cout << "\nPlaying an exciting game!\n";
        cout << "Do you want to play again? (y/n) ";
        cin >> repeat;
    }
    cout << "\nThanks for playing!\n";

    return 0;
}

Check Yourself

  1. What is the output from the following loop:
    int i = 10;
    while (i <= 10) {
       cout << i << " ";
    }
    
  2. How many times is the following loop executed?
    int counter = 1;
    while (counter > 20) {
       counter = counter + 1;
    }
    
  3. What is wrong with the following code?
    char repeat = 'y';
    while ('y' == repeat); {
        cout << "Do you want to run again? (y/n) ";
        // ... statements to execute
        cin >> repeat;
    }
    

4.3.5: Summary

  • Loops execute a block of code repeatedly
  • To stop (terminate) a loop you set a test condition
  • General loop structure:
    • Initialization code
    • Test condition -- evaluated during the loop
    • Loop body with some way to change the test condition
  • One loop statement we looked at is the while loop
  • For example:
    char repeat = 'y';
    while ('y' == repeat) {
        // ... statements to repeat
        cin >> repeat;
    }
    
  • Most programs have a main loop
  • Statements inside the loop repeat until the program exits
  • Several problems can occur when using a loop including:
    • Infinite loops: loops that "never" end
    • Missing curly braces
    • Empty statements

Check Yourself

  1. What is the purpose of a loop? (4.3.1)
  2. What are the three parts of any loop? (4.3.1)
  3. What is the syntax of a while statement? (4.3.2)
  4. What is the purpose of a loop test condition? (4.3.3)
  5. What is the purpose of loop initialization code? (4.3.3)
  6. What part of a loop is repeated? (4.3.3)
  7. What is meant by the term main programming loop? (4.3.4)
  8. What is the output from the following loop: (4.3.4)
    int i = 10;
    while (i <= 10) {
       cout << i << " ";
    }
    
  9. How many times is the following loop executed? (4.3.4)
    int counter = 1;
    while (counter > 20) {
       counter = counter + 1;
    }
    
  10. What is wrong with the following code? (4.3.4)
    char repeat = 'y';
    while ('y' == repeat); {
        cout << "Do you want to run again? (y/n) ";
        // ... statements to execute
        cin >> repeat;
    }
    

Wrap Up

Due Next:
A4-Making Selections (2/22/17)
  • When class is over, please shut down your computer
  • You may complete unfinished exercises at the end of the class or at any time before the next class.
Last Updated: March 21 2017 @00:13:03