So far, our Boolean expressions have consisted of only simple conditions, such as `balance <= 20000` in line 13 of Listing 8.4 or `(choice == "A")` in line 11 of Listing 8.5, with only one comparison operator. However, it is often beneficial to combine several simple conditions (sub-Boolean expressions) into one larger Boolean expression. Logical operators allow us to do exactly that.

C# contains three logical operators that are semantically equivalent to "and," "or," and "not" in our everyday language. The latter are used in Figure 8.12 as a general introduction to C#'s equivalents. Notice that each phrase could be part of a normal conversation, and that we intuitively understand their meaning.

The equivalents to and, or, and not from spoken English, are in the world of logic called logical AND, logical OR, and logical NOT. Logical AND is in C# symbolized by `&&` (two adjacent ampersands); logical OR is symbolized by `||` (two vertical lines); logical NOT is written as `!` (exclamation point).

The science of logic investigates the rules governing reliable deductions.

Note

It is important to realize that the meaning associated with |

A logical operator (`&&`, `||`, `!`) can only be applied to expressions of type `bool` and will always return a value of type `bool`. Another common term for logical operator is Boolean operator.

Table 8.2 provides a brief overview of the three operators. Notice that AND, OR, and NOT are sometimes referred to as conjunction, disjunction, and negation.

Logical operator | Other term used | C# Symbol | Number of operands | Example |
---|---|---|---|---|

AND | Conjunction | && | 2 (binary) | (5<3) && (10<20) |

OR | Disjunction | || | 2 (binary) | (mass < 800) || (distance >1000) |

NOT | Negation | ! | 1 (unary) | !(mass > 8000) |

Note

C# contains three additional logical operators apart from those mentioned in Table 8.2. They are called logical bitwise operators and are symbolized by single ampersand ( Because the logical bitwise operators are used less frequently than their cousins in Table 8.2. They will not be part of the main discussion here, but are presented at the end of this section. |

The logical AND operator (`&&`) is a binary operator and it combines two sub-Boolean expressions to form one larger Boolean expression (see Syntax Box 8.6).

## Syntax Box 8.6: Forming Larger Boolean Expressions with the |

By combining the two possible values (`true` and `false`) of `<Sub_Boolean_expression1>` with the two possible values of `<Sub_Boolean_expression2>`, we can form a truth table (see Table 8.3) with the four (2x2) different possible combinations and their resulting values when combined by the AND operator (`&&`).

A truth table provides a complete list of all the possible combinations of values of the variables in a Boolean expression and the resulting value for each combination. Tables 8.3, 8.4, 8.5, 8.6, 8.7, 8.8 and 8.9 are all examples of truth tables.

Value of sub_expression1 | Value of sub_expression2 | Value of larger Boolean expression: sub_expression1 && sub_expression2 | Example |
---|---|---|---|

false | false | false | (5>10) && (10<3) |

false | true | false | (5==2) && (10>2) |

true | false | false | (5!=0) && (3!=3) |

true | true | true | (7>4) && (9<10) |

Notice that only when both the original expressions of Table 8.3 are `true` does the resulting expression represent the value `true`; otherwise, the value is `false`.

Note

According to Appendix B (located at this book's Web site at www.samspublishing.com), all the comparison operators have higher precedence than the |

Recall the `balance` assessment program of Listing 8.4 presented earlier. As promised, it is possible to significantly simplify this program with the use of logical operators; let's see how.

The basic strategy is to reduce the number of required nested `if` statements by letting the Boolean expression of each `if` statement more precisely express the logic we are implementing. Recall our three categories from the Big Bucks Bank:

5000 balance 20000

60000 balance 75000

Neither A nor B

The Boolean expression of each `if` statement in Listing 8.4 was only partly able to describe (express) each category and had to be combined with Boolean expressions of other nested `if` statements to complete the picture. If we can somehow express the mathematical notation 5000 balance 20000 in one Boolean expression, we can write the logic shown in Figure 8.13 and reduce the number of nested `if` statements from four to two.

The code in Figure 8.13 has certainly simplified the multibranch `if-else` statement, but it has one serious drawback the Boolean expressions are invalid. It is not possible to use the mathematical notation 5000 balance 20000 in the C# source code as in the following:

if (5000 <= balance <= 20000) //Invalid

Any such comparisons must be broken down into sub-expressions with only one comparison operator and then connected fittingly with logical operators. Fortunately, it is possible by following this valid system to state the meaning contained in any logic expression.

But how do we express `5000 <= balance <= 20000` in this system, and how can we show that our new expression is correct? Well, many simpler expressions can be formed out of intuition and common sense, whereas more complicated expressions require knowledge from the science of logic. In our case, we try with common sense and convince ourselves that the meaning of

5000 <= balance <= 20000

had it been valid, is equivalent to

(5000 <= balance) && (balance <= 20000)

To prove that our common sense is correct, and that the two expressions in fact are identical, we can compare their truth tables. The truth table for `5000` <= `balance` <= `20000` is shown in Table 8.4. Notice that each of the first two columns must be filled out in the standard fashion introduced in Table 8.3, so they contain exactly the same entries.

5000 balance | balance 20000 | 5000 balance 20000 |
---|---|---|

false | false | false |

false | true | false |

true | false | false |

true | true | true |

The truth table for `&&` is simply constructed by copying the values given in `&&`'s truth table of Table 8.3 and inserting `balance >= 5000` and `balance <= 20000` in the place of the sub-expressions. This results in Table 8.5.

balance >= 5000 | balance <= 20000 | 5000 <= balance && balance <= 20000 |
---|---|---|

false | false | false |

false | true | false |

true | false | false |

true | true | true |

Because the entries of the two tables are identical, we conclude that our common sense indeed was correct, in that

5000 balance 20000

is equivalent to

5000 <= balance && balance <= 20000

and, consequently, we can simplify the nested `if` statements of our Big Bucks Bank application in a similar fashion to that shown in Figure 8.13. Lines 11 16 of Listing 8.7 present the resulting multibranch `if-else` statements.

01: using System; 02: 03: class CompactBalanceAssessment 04: { 05: public static void Main() 06: { 07: decimal balance; 08: 09: Console.Write("Enter balance: "); 10: balance = Convert.ToDecimal(Console.ReadLine()); 11: if(balance >= 5000 && balance <= 20000) 12: Console.WriteLine("Balance is in category A"); 13: else if(balance >= 60000 && balance <= 75000) 14: Console.WriteLine("Balance is in category B"); 15: else 16: Console.WriteLine("Balance is in category C"); 17: } 18: }

The output is the same as that from Listing 8.4.

By utilizing the `&&` operator in lines 11 and 13, we reduce the number of nested `if-else` statements from four to two. This is possible since we have shown that:

balance >= 5000 && balance <= 20000is logically equivalent to5000 >= balance >= 20000

and that:

balance >= 5000 && balance <= 20000is logically equivalent to5000 >= balance >= 20000

The logical operator OR, written with two vertical lines `||`, is a binary operator and, as such, combines two operands, as shown in Syntax Box 8.7.

## Syntax Box 8.7 Forming Larger Boolean Expressions with the |

The truth table of the logical OR operator shown in Table 8.6 tells us that only if both sub-expressions are `false` (first row) will the larger expression be `false`; otherwise, it will be `true`. This nicely fits in with our usual connotation of the word "or." For example in the following sentence

both conditions need to be `false` for today not to be a weekend.

Value of sub-expression1 | Value of sub-expression2 | sub-expression1 || sub-expression2 |
---|---|---|

false | false | false |

false | true | true |

true | false | true |

true | true | true |

Example:

Sometimes theatres and cinemas offer discounted tickets to people who fit into a certain age category. In this case, a person must be either less than 15 or more than 65 years old to get a discounted ticket. Listing 8.8 utilizes the `||` operator along with this rule to determine whether a person is entitled to a discount.

`01: using System; 02: 03: class DiscountOrNot 04: { 05: public static void Main() 06: { 07: int age; 08: 09: Console.Write("Enter your age: "); 10: age = Convert.ToInt32(Console.ReadLine()); 11: if ((age < 15) || (age > 65)) 12: Console.WriteLine("Congratulations! You get a discount"); 13: else 14: Console.WriteLine("Sorry no discount for you"); 15: } 16: } Enter your age: 10<enter> Congratulations! You get a discount `

Line 11 utilizes the `||` operator to determine whether `age` is less than 15 or greater than 65. If this is the case, line 12 is executed; otherwise, the flow of control is passed to line 14.

You might use as many logical operators in one Boolean expression as you want, but must then keep in mind that the `&&` operator has a higher precedence than the `||` operator. Consequently, you might need to apply parentheses to get a correct result.

Example:

A programmer wants to implement a simple program that sifts through a list of cars for sale in a database to locate cars with suitable characteristics. In this case, the programmer is interested in the `price`, `age`, and `maxSpeed`. The `price` is the main concern, so as long as the `price` is less than $5,000.00, she is happy if just one of the following two criteria is `true`:

`age`< 10 years`maxSpeed`> 120 mph.

The following is a first attempt to implement these rules:

if (price < 5000 && age < 10 || maxSpeed > 120) //Incorrect first attempt

However, due to the higher precedence of the `&&` operator, the Boolean expression is evaluated as

if ((price < 5000 && age < 10) || maxSpeed > 120)

which represents a different logic. It locates all cars with a `maxSpeed` greater than 120, disregarding the `price` and `age`. All other cars will only be selected if both (`price < 5000)` and (`age < 10`) are `true`. To rectify the problem, we need to apply a couple of parentheses, forcing the `||` operator to be applied first:

if (price < 5000 && (age < 10 || maxSpeed > 120)) //Correct

Let's compare the truth tables (see Table 8.7) of the invalid and the valid car evaluation expressions to pinpoint the differences between them. Notice that the differences between the two expressions appear in the second and fourth rows, the rest are identical.

Price < 5000 | Age < 10 | MaxSpeed > 120 | (price < 5000 && age < 10 || maxSpeed > 120) | (price < 5000 && (age < 10 || maxSpeed > 120)) |
---|---|---|---|---|

false | false | false | false | false |

false | false | true | true | false |

false | true | false | false | false |

false | true | true | true | false |

true | false | false | false | false |

true | false | true | true | true |

true | true | false | true | true |

true | true | true | true | true |

Note

To write down all the combinations of |

When the program evaluates a Boolean expression containing the `&&` operator, such as

(distance == 1000) && (mass ==3000)

it will first evaluate `(distance == 1000)`. If this part turns out to be `false`, the compiler knows that according to the `&&` truth table, the whole expression must be `false`, irrespective of the value the second part (`(mass == 3000)`). To save time, the compiler skips the evaluation of `(mass == 3000)`. This mechanism is referred to as short-circuiting.

Similarly, if the program contains the following `||` expression

(distance == 1000) || (mass == 3000)

and the first part (`(distance == 1000)`) is evaluated to be `true`, the latter part will be ignored, because its value, according to the OR truth table, will not make any difference to the value of the full expression.

C# contains two additional logical operators called bitwise AND symbolized with a single ampersand (`&`) and bitwise OR symbolized by a single vertical line (`|`). The truth tables for `&` and `|` are identical to those of `&&` and `||`, respectively. However, `&` and `|` do not cause short circuit evaluation and will, therefore, perform a fraction slower than their short-circuiting equivalents.

In most cases, `&&` and `||` will be the preferred operators to use, but in rare instances, you might want the program to complete the evaluation of a Boolean expression, even if it is not needed to determine the value of the overall Boolean expression.

For example, recall the increment (`++`) and decrement (`--`) arithmetic operators from Chapter 7. Just as they can be part of a longer arithmetic expression, they can also be part of a Boolean expression, such as the following:

if ((++distance == 1000) && (++count <= 10))

whenever `(++count <= 10)` is evaluated, `count` is first incremented by one and then compared with `10`. However, due to the short-circuiting nature of `&&`, `(++count <= 10)` is only evaluated if `(++distance == 1000)` is `true`. As a consequence, `count` will only be incremented by one when `distance` is equal to `1000`, which was probably not what the programmer had in mind. To make sure that the increment always takes place when this line is executed, the programmer can make use of the bitwise operator `&`:

if ((++distance == 1000) & (++count <= 10))

Tip

Even though source code with increment and decrement operators applied inside longer expression might look smart and sophisticated at first glance, they usually represent bug-prone code, difficult to read and, hence, not worthwhile. Thus, instead of writing if ((++distance == 1000) & (++count <= 10)) break the line up into three lines: ++distance; ++count; if ((distance == 1000) && (count <= 10)) There is no doubt as to how these three lines are processed. |

Sometimes, programmers use a certain style for constructing a Boolean expression that requires short-circuit evaluation to avoid runtime errors. This is exemplified in the following line:

if ((speed != 0) && ((distance / speed) > 100))

In general, division by zero produces an infinitely large value and a runtime exception. Thus, if `speed` in the expression is equal to zero, the second part of the expression (`((distance / speed) > 100)`) generates a runtime exception. However, because `(speed != 0)`, along with the short circuiting of the `&&` operator, only allows the second part to be executed if `speed` is different from zero, the line will never generate a runtime exception due to this problem. This would obviously not be the case had we applied the bitwise `&` operator instead.

The `||` operator is sometimes referred to as inclusive OR and is, in many cases, equivalent to the meaning of "or" in our spoken language. For example, if I ask you

Would you like salt or pepper?

"or" has the same meaning as `||`. It is implicitly understood that you can choose just the salt or just the pepper or even both; all three cases would lead to `true`, similar to our truth table for `||` (see Table 8.6). Only if you decide against both offers does the proposition become `false`. But what about the next question:

Would you like to go to the cinema or the theatre tonight?

where the intent is to either go to the cinema or the theatre but not both. Thus, if you choose neither or if you choose both, the proposition is `false`. Only if you choose just the cinema or just the theatre will it be `true`. This meaning of "or" is referred to as exclusive OR and is symbolized by `^` in C#. The truth table is shown in Table 8.8.

Value of sub-expression1 | Value of sub-expression2 | sub-expression1 ^ sub-expression2 |
---|---|---|

false | false | false |

false | true | true |

true | false | true |

true | true | false |

Note

The ambiguous connotation of "or" in our spoken language can sometimes have important implications. Consider this scenario: Your house is damaged by fire and, during the fire, a thief takes all your belongings. After this ordeal, you rush to check your insurance policy and are relieved when you see the following line: "…and you are insured against theft or fire…" Then it suddenly strikes you (because you've just been reading your favorite chapter about logical operators in some book about C#) that the insurance company might interpret "or" in the contract as exclusive "or." You're freaked out by the thought of the implications: Because the two misfortunes happened at the same time, you get zilch compensation. Only if the house is on fire exclusively, or if the house is broken into exclusively will you get a payment. |

The logical NOT (`!`)operator is, as opposed to the binary operators `&&` and `||`, a unary operator, as shown in Syntax Box 8.8. Just as the unary minus operator `-` reverses the sign of a numerical expression, the logical NOT operator inverts the truth value of the Boolean expression to which it is applied. In other words, if the value of `myBooleanExpression` is `true`, `!myBooleanExpression` is `false`, and vice versa. This is displayed in Table 8.9.

## Syntax Box 8.8 Forming Boolean Expressions with the |

Note

A popular name for the |

Note

The |

Value of sub-expression | !sub-expression |
---|---|

false | true |

true | false |

In many cases, Boolean expressions are clearer if they don't involve negations. Fortunately, it is often possible to steer clear of the negation operator by rearranging the operands and by carefully selecting the comparison operators applied in a Boolean expression. Table 8.10 provides a few examples.

Boolean expression with ! operator | Clearer equivalent Boolean expression without the ! operator |
---|---|

!(x == 10) | (x != 10) |

!(x > 10) | (x <= 10) |

!(x <= 10) | (x > 10) |

Note

As opposed to ! (10 > 20) //Valid ! 10 > 20 //Invalid The first expression is valid because the parentheses enclose a Boolean expression. However, the second expression is interpreted as |

If you are constructing an `if-else` statement and are trying to remove an `!` operator stalking the associated Boolean expression, the following method might be helpful.

Consider the following two code snippets.

The only effect of the `!` operator in this `if-else` statement is to redirect the flow from the `true` `if` part to the `false` `else` part and vice versa. Thus, by removing the `!` operator as well as swapping the contents of the `if` part and the `else` part, the logic of the `if-else` statements remains unchanged.

Until now, we have merely tried to avoid our poor and lonely `!` operator. Isn't it useful for anything? Yes, it is useful in cases where it is impossible to exchange one comparison operator with another or swapping statements in `if-else` statements as demonstrated above. We bump into those cases when working with methods returning a value of type `bool`. Recall our `TextAnalyzer.cs` program from Listing 7.8, in Chapter 7. It utilized a whole host of methods found in the `System.Char` structure, one of which was the `IsWhiteSpace()` method. It returned the value `true` if the character provided as an argument was a whitespace character; otherwise, it returned `false`. But what if we wanted to count the non-whitespace characters of a text? Because there is no `IsNotWhiteSpace()` method or something similar, we can utilize the `!` operator instead to simulate such a method. This is done in line 17 of Listing 8.9, which counts all non-whitespace characters of a text.

01: using System; 02: 03: class CharacterCounter 04: { 05: public static void Main() 06: { 07: string myText; 08: int charCount = 0; 09: char ch; 10: int index = 0; 11: 12: Console.WriteLine("Enter some text"); 13: myText = Console.ReadLine(); 14: while (index < myText.Length) 15: { 16: ch = myText[index]; 17: if (!char.IsWhiteSpace(ch)) 18: charCount++; 19: index++; 20: } 21: Console.WriteLine("Number of non-white-space characters: {0:N0} ", charCount); 22: } 23: }

Sample 1:

` Enter some text Beethoven<enter> Number of non-white-space characters: 9 `

Sample 2:

` Enter some text B e e th o v e n<enter> Number of non-white-space characters: 9 `

As long as `(index < myText.Length)` in line 14 is `true`, the compound statement of the `while` statement spanning from line 15 to line 20 is repeated. Because `index` is initialized to 0 in line 10, and every repetition of the compound statement increments `index` by 1 in line 19, the loop is repeated `myText.Length` times, allowing the algorithm to analyze every position of `myText` in lines 17 and 18. We are able to detect all non-whitespace characters by applying the `!` operator in line 17. Every time a non-whitespace character is encountered, `charCount` is incremented by one.

C Primer Plus (5th Edition)

ISBN: 0672326965

EAN: 2147483647

EAN: 2147483647

Year: 2000

Pages: 286

Pages: 286

Authors: Stephen Prata

Similar book on Amazon

flylib.com © 2008-2017.

If you may any questions please contact us: flylib@qtcs.net

If you may any questions please contact us: flylib@qtcs.net