Operator Precedence in C++


TL ; DR:

  • When we string operations together, C++ must know which one to do first. This is called operator precedence.


  • * and / are performed before + and -:

  • cout << 1 + 2 * 3; // Prints 7
    cout << 6 - 4 / 2; // Prints 4
    cout << 5 * 4 - 2 / 2; // Prints 19
    

  • We can add () to force an operation to be performed first:

    cout << (1 + 2) * 3; // Prints 9
    cout << (6 - 4) / 2; // Prints 1
    cout << 5 * (4 - 2) / 2; // Prints 5
    




Full lesson:

When we string operations together, C++ must know which one to do first. This is called operator precedence.

This is the hierarchy from highest precedence to lowest precedence:

  • Parentheses are always respected
  • Exponentiation (raise to a power)
  • Multiplication, Division and Remainder
  • Addition and Subtraction
  • Left to right


First example:

cout << 1 + 2 * 3; // Output: 7

Multiplication is executed before addition, so:

1 + 2 * 3 = 1 + 6 = 7

Second example:

cout << (1 + 2) * 3; // Output: 9

What's inside parentheses is executed before multiplication, so:

(1 + 2) * 3 = 3 * 3 = 9

Third example:

cout << 6 / 4 * 3 + 5; // Output: 9.5

Multiplication and division come before addition. Also, multiplication and division have the same priorty so they are executed from left to right:

6 / 4 * 3 + 5 = 1.5 * 3 + 5 = 4.5 + 5 = 9.5

Forth example:

cout << 6 / ((4 + 2) / 3); // Output: 3

Computer sees parentheses so it looks at it like this:

6 / ((4 + 2) / 3) = 6 / x, where x = (4 + 2) / 3

I have to compute x first. Parantheses are executed before division:
(4 + 2) / 3 = 6 / 3 = 2

I can replace x with 2:
6 / ((4 + 2) / 3) = 6 / 2 = 3


Assignment
Follow the Coding Tutorial and let's practice with operator precedence!


Hint
Look at the examples above if you get stuck.


Introduction

In this lesson, we will explore the concept of operator precedence in C++. Operator precedence determines the order in which different operations are performed in an expression. Understanding operator precedence is crucial for writing correct and efficient code, as it helps avoid logical errors and ensures that expressions are evaluated as intended.

Operator precedence is particularly useful in scenarios where multiple operations are combined in a single expression. For example, mathematical calculations, logical operations, and complex conditionals often involve multiple operators. Knowing the precedence rules allows you to predict the outcome of these expressions accurately.

Understanding the Basics

Before diving into the details of operator precedence, let's review some fundamental concepts:

  • Operators: Symbols that perform operations on variables and values. Examples include +, -, *, and /.
  • Operands: The values or variables on which operators act. For example, in the expression 3 + 5, 3 and 5 are operands.
  • Expressions: Combinations of operators and operands that produce a value. For example, 3 + 5 * 2 is an expression.

Understanding these basics is essential because operator precedence directly affects how expressions are evaluated. Without a clear grasp of these concepts, it can be challenging to predict the outcome of complex expressions.

Main Concepts

Operator precedence in C++ follows a specific hierarchy, from highest to lowest precedence:

  • Parentheses: Operations inside parentheses are always performed first.
  • Exponentiation: Raising a number to a power (not a standard operator in C++, but can be implemented using functions).
  • Multiplication, Division, and Remainder: These operations are performed next, from left to right.
  • Addition and Subtraction: These operations are performed after multiplication, division, and remainder, from left to right.

Let's see how these rules apply to some examples:

Example 1

cout << 1 + 2 * 3; // Output: 7

In this example, multiplication is performed before addition:

1 + 2 * 3 = 1 + 6 = 7

Example 2

cout << (1 + 2) * 3; // Output: 9

Here, parentheses force the addition to be performed before multiplication:

(1 + 2) * 3 = 3 * 3 = 9

Example 3

cout << 6 / 4 * 3 + 5; // Output: 9.5

Multiplication and division are performed before addition, and they are executed from left to right:

6 / 4 * 3 + 5 = 1.5 * 3 + 5 = 4.5 + 5 = 9.5

Example 4

cout << 6 / ((4 + 2) / 3); // Output: 3

Parentheses change the order of operations:

6 / ((4 + 2) / 3) = 6 / 2 = 3

Examples and Use Cases

Let's explore more examples and real-world use cases where operator precedence is crucial:

Example 5: Complex Mathematical Expression

cout << (5 + 3) * 2 - 4 / 2; // Output: 14

Here, parentheses force the addition to be performed first, followed by multiplication, division, and subtraction:

(5 + 3) * 2 - 4 / 2 = 8 * 2 - 2 = 16 - 2 = 14

Example 6: Logical Operations

bool result = (true || false) && false; // Output: false

Logical OR (||) is performed before logical AND (&&):

(true || false) && false = true && false = false

Common Pitfalls and Best Practices

When working with operator precedence, it's essential to be aware of common pitfalls and follow best practices:

  • Misunderstanding Precedence: One common mistake is misunderstanding the precedence rules, leading to incorrect results. Always refer to the precedence hierarchy when in doubt.
  • Using Parentheses: To avoid ambiguity and ensure the correct order of operations, use parentheses liberally. This makes the code more readable and less error-prone.
  • Code Readability: Write expressions in a way that is easy to understand. Avoid overly complex expressions that can confuse readers.

Advanced Techniques

For advanced users, understanding operator precedence can help optimize code and implement more complex algorithms. For example, you can use precedence rules to simplify expressions and reduce the number of operations performed.

Code Implementation

Let's implement a C++ program that demonstrates operator precedence with various examples:

#include <iostream>

int main() {
    // Example 1
    std::cout << "Example 1: " << 1 + 2 * 3 << std::endl; // Output: 7

    // Example 2
    std::cout << "Example 2: " << (1 + 2) * 3 << std::endl; // Output: 9

    // Example 3
    std::cout << "Example 3: " << 6 / 4 * 3 + 5 << std::endl; // Output: 9.5

    // Example 4
    std::cout << "Example 4: " << 6 / ((4 + 2) / 3) << std::endl; // Output: 3

    // Example 5
    std::cout << "Example 5: " << (5 + 3) * 2 - 4 / 2 << std::endl; // Output: 14

    // Example 6
    bool result = (true || false) && false;
    std::cout << "Example 6: " << result << std::endl; // Output: false

    return 0;
}

Debugging and Testing

When debugging code related to operator precedence, consider the following tips:

  • Print Intermediate Results: Print intermediate results to verify the order of operations and ensure correctness.
  • Use a Debugger: Use a debugger to step through the code and observe the evaluation of expressions.
  • Write Test Cases: Write test cases to validate the behavior of expressions with different combinations of operators.

Example test case:

#include <cassert>

void test_operator_precedence() {
    assert((1 + 2 * 3) == 7);
    assert(((1 + 2) * 3) == 9);
    assert((6 / 4 * 3 + 5) == 9.5);
    assert((6 / ((4 + 2) / 3)) == 3);
    assert(((5 + 3) * 2 - 4 / 2) == 14);
    assert(((true || false) && false) == false);
}

int main() {
    test_operator_precedence();
    std::cout << "All tests passed!" << std::endl;
    return 0;
}

Thinking and Problem-Solving Tips

When approaching problems related to operator precedence, consider the following strategies:

  • Break Down Complex Expressions: Break down complex expressions into smaller parts and evaluate them step-by-step.
  • Use Parentheses: Use parentheses to clarify the order of operations and avoid ambiguity.
  • Practice: Practice solving problems with different combinations of operators to reinforce your understanding of precedence rules.

Conclusion

In this lesson, we explored the concept of operator precedence in C++. We discussed the hierarchy of operators, provided examples to illustrate the rules, and highlighted common pitfalls and best practices. Understanding operator precedence is essential for writing correct and efficient code, and it helps avoid logical errors in complex expressions.

By mastering operator precedence, you can confidently write and debug expressions in C++, ensuring that your code behaves as expected. Keep practicing and exploring further applications to deepen your understanding of this fundamental concept.

Additional Resources

For further reading and practice problems related to operator precedence, consider the following resources: