Search code examples
if-statementlanguage-agnosticlogical-operatorscontrol-flowdemorgans-law

Why does non-equality check of one variable against many values always return true?


I have a variable v in my program, and it may take any value from the set of values

"a", "b", "c", ..., "z"

And my goal is to execute some statement only when v is not "x", "y", or "z".

I have tried,

  • for C-like languages (where equality operators compare the actual string values; e.g. , , )

    if (v != "x" || v != "y" || v != "z")
    {
        // the statements I want to be executed
        // if v is neither "x", nor "y", nor "z"
    }
    
  • for Pascal-like languages (e.g. )

    IF (v != 'x' OR v != 'y' OR v != 'z') THEN
        -- the statements I want to be executed
        -- if v is neither "x", nor "y", nor "z"
    END IF;
    

The statements inside the if condition always get executed. Am I doing anything wrong?


Solution

  • Use &&/AND/and, not ||/OR/or:

    v != "x" && v != "y" && v != "z"
    

    Problem

    If an if block is always executed, the condition for the if block always evaluates to true. The logical expression must be wrong.

    Let us consider v != "x" || v != "y" || v != "z" for each value of v.

    • When v = "x",

      v != "x" becomes "x" != "x", which is false.
      v != "y" becomes "x" != "y", which is true.
      v != "z" becomes "x" != "z", which is true.

      The expression evaluates to false || true || true, which is true.

    • When v = "y", the expression becomes

        "y" != "x" || "y" != "y" || "y" != "z"
      

      or true || false || true, which is true.

    • When v = "z", the expression becomes

        "z" != "x" || "z" != "y" || "z" != "z"
      

      or true || true || false, which is true.

    • For any other value for v, the expression evaluates to true || true || true, which is true.

    Alternatively, consider the truth-table:

           │     A          B          C      │
      v    │  v != "x"   v != "y"   v != "z"  │  A || B || C
    ───────┼──────────────────────────────────┼──────────────
     "x"   │    false      true       true    │     true
     "y"   │    true       false      true    │     true
     "z"   │    true       true       false   │     true
    other  │    true       true       true    │     true
    

    As you can see, your logical expression always evaluates to true.

    Solution

    What you want to do is, find a logical expression that evaluates to true when

    (v is not "x")and(v is not "y")and(v is not "z").

    The correct construction is,

    • for C-like languages (eg. , -(may need the strict equality operator !==), )

        if (v != "x" && v != "y" && v != "z")
        {
            // the statements I want to be executed
            // if v is neither "x", nor "y", nor "z"
        }
      
    • for Pascal-like languages

        IF (v != 'x' AND v != 'y' AND v != 'z') THEN
            -- the statements I want to be executed
            -- if v is neither "x", nor "y", nor "z"
        END IF;
      

    De Morgan's law

    By De Morgan's law, the expression can also be rewritten as (using C-like syntax)

    !(v == "x" || v == "y" || v == "z")
    

    meaning

    not((v is "x")or(v is "y")or(v is "z")).

    This makes the logic a bit more obvious.

    Specific languages

    Some languages have specific constructs for testing membership in sets, or you can use array/list operations.