Understanding Boolean Logic: The True and False of Programming - Part 2

Understanding Boolean Logic: The True and False of Programming - Part 2

Learning Boolean Logic: Distinguishing Between Real and Unreal Elements in Programming

Operators

Boolean operators are used in programming to perform logical operations on boolean values (True or False). Python, like many programming languages, supports several boolean operators for this purpose:

  1. and: The and operator returns True if both operands are True, and False otherwise. If any operand is False, the result is False.
XYX and Y
000
010
100
111
  1. or: The or operator returns True if at least one of the operands is True, and False if both operands are False.
XYX OR Y
000
011
101
111
  1. not: The not operator returns the opposite boolean value of its operand. If the operand is True, not makes it False, and if the operand is False, not makes it True.
Xnot X
10
00

Commutativity

Boolean operators in Python exhibit commutative behavior for and and or operations:

  1. Commutativity of and (&): The and operator in Python is commutative because the order in which you evaluate the operands doesn't affect the result. This means that A and B is equivalent to B and A. Both expressions will yield the same result.

     True and False   # False
     False and True   # False
    
  2. Commutativity of or (|): Similarly, the or operator in Python is also commutative. A or B is equivalent to B or A. Both expressions will yield the same result.

     True or False    # True
     False or True    # True
    

Boolean operators exhibit commutative behavior because they are logical operations based on mathematical principles. This property allows you to rearrange boolean expressions involving and and or operators without changing the logical outcome, making it easier to work with complex conditions and improving code readability.

Distributivity

In Boolean algebra, distributivity is a property that describes how logical operations interact with each other. Distributivity applies to the and and or operators in Boolean algebra. There are two forms of distributivity: the distributive law for and over or, the distributive law for or over and. Here's how they work:

  1. Distributive Law for and over or:

    The distributive law for and over or states that (A and B) or (A and C) is equivalent to A and (B or C). In other words, you can distribute the and operation over the or operation.

     (A and B) or (A and C)  ≡  A and (B or C)
    

    This means that if either A and B or A and C is true, then A must be true, and either B or C must be true.

  2. Distributive Law for or over and:

    The distributive law for or over and states that (A or B) and (A or C) is equivalent to A or (B and C). In other words, you can distribute the or operation over the and operation.

     (A or B) and (A or C)  ≡  A or (B and C)
    

    This means that if either A or B and A or C is true, then A must be true, or both B and C must be true.

These distributive laws are fundamental in boolean algebra and are often used when simplifying boolean expressions or working with complex logical conditions. They provide a way to reorganize and simplify expressions while preserving logical equivalence.

Associativity

Associativity refers to the order in which operators of the same precedence are applied in an expression. In boolean algebra, the and and or operators exhibit associativity.

  1. Associativity of and (&):

    The and operator in boolean algebra is left-associative. This means that if you have a series of and operations in an expression, they are evaluated from left to right. This property ensures that you can chain multiple and operations together, and the result will be the same regardless of how you group them.

    For example:

     A and B and C
    

    This expression is evaluated as (A and B) and C, but you can also write it as A and (B and C), and the result will be the same.

  2. Associativity of or (|):

    The or operator in boolean algebra is also left-associative. Similar to and, this means that if you have a series of or operations in an expression, they are evaluated from left to right. You can chain multiple or operations together, and the result will be the same regardless of how you group them.

    For example:

     A or B or C
    

    This expression is evaluated as (A or B) or C, but you can also write it as A or (B or C), and the result will be the same.

Associativity is an important property in boolean algebra because it ensures that expressions with multiple operators of the same precedence are evaluated consistently, making it easier to reason about and write boolean expressions.

De Morgan's Theorem

De Morgan's Theorem is a fundamental concept in boolean algebra, named after the British mathematician and logician Augustus De Morgan. The theorem describes the relationship between negations (NOT) and logical conjunctions (AND) and disjunctions (OR). There are two forms of De Morgan's Theorem: one for negating a conjunction and one for negating a disjunction. Here they are:

  1. De Morgan's Theorem for Negating a Conjunction (AND):

    The theorem states that the negation of a conjunction (AND) is equivalent to the disjunction (OR) of the negations of the individual terms. In other words, if you have a statement like "not (A and B)," you can rewrite it as "(not A) or (not B)."

    Mathematically, it can be expressed as:

     not (A and B) ≡ (not A) or (not B)
    

    This means that if either A is false or B is false (or both), then "not (A and B)" is true.

  2. De Morgan's Theorem for Negating a Disjunction (OR):

    The theorem states that the negation of a disjunction (OR) is equivalent to the conjunction (AND) of the negations of the individual terms. In other words, if you have a statement like "not (A or B)," you can rewrite it as "(not A) and (not B)."

    Mathematically, it can be expressed as:

     not (A or B) ≡ (not A) and (not B)
    

    This means that both A must be false and B must be false for "not (A or B)" to be true.

De Morgan's Theorem is a useful tool for simplifying boolean expressions and is often employed when working with logic gates in digital electronics, programming, and formal logic. It allows you to transform complex logical expressions into equivalent forms that may be easier to work with or understand.

Miscellaneous

  • The expression not(x < y) is equivalent to x >= y.

  • The expression not(x <= y) is equivalent to x > y.

  • The expression not(x > y) is equivalent to x <= y.

  • The expression not(x >= y) is equivalent to x < y.

  • The statement not(not A) is equivalent to A.

Operator Precedence

In Python and many other programming languages, boolean expressions are typically evaluated from left to right, following a short-circuit evaluation strategy. This means that the interpreter or compiler will stop evaluating the expression as soon as the result is determined, without evaluating unnecessary parts of the expression.

Here are some key points regarding left-to-right evaluation and short-circuiting in Boolean expressions:

  1. Logical AND (and): For a sequence of conditions joined by and, if any condition evaluates to False, the entire expression is False. In this case, the interpreter stops evaluating the remaining conditions because the overall result is already known.

    Example:

     result = A and B and C
    

    If A is False, the interpreter will not evaluate B and C because the result is already False.

  2. Logical OR (or): For a sequence of conditions joined by or, if any condition evaluates to True, the entire expression is True. The interpreter stops evaluating the remaining conditions because the overall result is already known.

    Example:

     result = A or B or C
    

    If A is True, the interpreter will not evaluate B and C because the result is already True.

  3. Short-Circuiting: The behavior described above is known as short-circuiting. It can be useful for improving performance and avoiding unnecessary computations in cases where the final result can be determined early in the evaluation process.

  4. Order of Evaluation: The left-to-right order of evaluation is important when the expressions have side effects, such as function calls or variable assignments, as the side effects will occur in the order of evaluation.

It's important to be aware of short-circuiting behavior when writing boolean expressions in your code. It can be leveraged to optimize performance and avoid potential errors in cases where further evaluation is unnecessary due to the early determination of the result.

💡
When in doubt, or to be absolutely sure, use parentheses!Also, use parentheses to make your code more human readable! eg: Instead of a < b or a > c and not x or y we can write as (a < b) or ((a > c) and (not x)) or y

Short Circuit Evaluation

Short-circuit evaluation is a behavior in boolean expressions where the interpreter or compiler does not evaluate the entire expression when the final outcome can be determined based on the initial part of the expression. This optimization is often used in programming languages like Python to improve efficiency and avoid unnecessary computations. Short-circuit evaluation occurs in two common scenarios: with logical AND (and) and logical OR (or) operators.

  1. Logical AND (and) Short-Circuit Evaluation:

    In a logical AND expression (and), if the left operand evaluates to False, there is no need to evaluate the right operand because the entire expression will always be False. The right operand is short-circuited.

    Example:

     result = A and B
    

    If A is False, B will not be evaluated because the result is already known to be False.

  2. Logical OR (or) Short-Circuit Evaluation:

    In a logical OR expression (or), if the left operand evaluates to True, there is no need to evaluate the right operand because the entire expression will always be True. The right operand is short-circuited.

    Example:

     result = A or B
    

    If A is True, B will not be evaluated because the result is already known to be True.

Short-circuit evaluation is particularly useful when dealing with expressions involving conditions that are computationally expensive or have side effects (e.g., function calls) that you want to avoid when the result is already known. It allows for more efficient and optimized code.

Keep in mind that not all programming languages use short-circuit evaluation, but many popular languages, including Python, do support this behavior. It's important to be aware of short-circuiting when writing code and to design expressions with it in mind to ensure both correctness and efficiency.

Scenario: There is some data feed that lists a stock symbol, and some financial data.

Your job is to monitor this feed, looking for specific stock symbols defined in some watch list, and react only if the current stock price is above some threshold. Getting the current stock price has an associated cost.

If Boolean expressions did not implement short-circuiting, you would probably write:

if symbol in watch_list:
    if price(symbol) > threshold:
        # do something
#since calling the price() method has a cost, we would only want to call it if the symbol was on our watch list

But because of short-circuit evaluation you could write this equivalently as:

if symbol in watch_list and price(symbol) > threshold:
    # do something

In conclusion, understanding Boolean logic is essential for efficient and effective programming. By mastering operators, commutativity, distributivity, associativity, De Morgan's Theorem, and short-circuit evaluation, programmers can write more optimized and readable code. Being aware of these concepts and properties allows for better manipulation and simplification of complex logical expressions, ultimately improving the overall quality of your code.

Did you find this article valuable?

Support TechWhisperer by becoming a sponsor. Any amount is appreciated!