3.1 Decisions and Relational Expressions

In order to make decisions, Processing uses expressions of type boolean. Recall that there are two values of type boolean: true and false. Just as we can for other primitive types, we can create and use variables of type boolean.

Example 1

This program demonstrates creating and printing of boolean variables.
boolean x = false;
boolean y = true;
println("x: " + x + " y: " + y);
This program will print

One of the most common ways that we create boolean values is by evaluating a comparison of other types of values.

Example 2

(a) The expression 2 < 3 has the value true.
(b) The expression -6.3 > 1.75 has the value false.

     Expressions like the ones shown in this example are called relational expressions because their values depend on the relationship between other values. The example used the relational operators < and >. Processing has a total of six relational operators. They are shown in the following table.


     Operators that are constructed from two characters must not have embedded blanks and must be in the order shown. The == operator is a frequent cause of errors in Processing programs; people often omit the second equals sign. The operator is written as it is to distinguish it from the assignment operator.
     Values of any of the primitive types can be compared in relational expressions. Values of type boolean can only be compared for equality or inequality; comparison of the relative sizes of boolean values is not meaningful.
     Values of type char are ordered according to a collating sequence. Processing's collating sequence is determined by the ordering of characters in the Unicode encoding system. A character that precedes another in the collating sequence is considered to be less than the other. Usually, comparison of characters is used with alphabetic characters and the results are what you would expect. The Unicode encodings for letters follow alphabetic order so that 'A' < 'B' < ... < 'Z' and 'a' < 'b' < ... < 'z'. One must, however, be careful with these comparisons as all upper case letters have encodings that are smaller than any of the lower case letters. In addition, accented letters such as é, ü, or ç have encodings that are larger than any unaccented letters. Life is never simple.1
     Luckily, it is rare that a programmer needs to be concerned with the details of Unicode encodings of characters. For most situations, all that you need to know is that

• '0' < '1' < '2' < ... < '9'
• 'A' < 'B' < 'C' < ... < 'Z'
• 'a' < 'b' < 'c' < ... < 'z'
• A blank precedes any digit or letter.
• All digits precede all letters.
• All upper case letters precede all lower case letters.
1More details can be found in Appendix C.

Example 3

(a) The expression
          'T' < 't'
     has the value true because upper case letters have smaller Unicode than lower case letters.
(b) To evaluate the expression
          '#' < '+'
     we need to know the Unicode encoding values of these characters. These values can be found in the table on page 600. From the table, we can see that the numerical value of the encoding of '#' is 35 while that of '+' is 43. Thus the expression has the value true because 35 < 43.

     Types can be mixed in relational expressions just as they can in arithmetic expressions. Any char values are compared to numerical values using their Unicode encoding values. Values of type boolean cannot be compared to values of any other type.
     If arithmetic and relational operators are both included in an expression, the arithmetic operators all have a higher precedence than the relational operators.

Example 4

The expression 2.0 + 3 < 2 * 3 would be evaluated as follows:
                    2.0 + 3 < 2 * 3 => 2.0 + 3 < 6
                                            => 5.0 < 6
                                            => true

Exercises 3.1

  1. For each legal expression, state its value. For each illegal expression, state the reason that it is illegal.
    1. (2 + (-5)) != 3
    2. 'm' < = 'p'
    3. 'Q' == 'q'
    4. '*' < '*'
    5. 8.23 =< 8.2300
    6. (7 / 3) = 2
    7. false == 0
    8. (25 % 4) >= 1

  2. State, with reasons, what this program will print.
    boolean perhaps, maybe;
    perhaps = 4 < 5;
    maybe = -17 % 4 == 1;
    println("perhaps: " + perhaps);
    println("maybe : " + maybe);
  3. For each expression, state whether it is true or false.
    1. 'q' < 'm'
    2. 'G' > 'K'
    3. 'a' < 'Z'
    4. '5' < 'v'
    5. 'q' > '7'
    6. '9' < ' '
    7. 'X' < 's'
    8. 'i' < 'I'

  4. Determine the value of each expression.
    1. 7 / 3 < 7 / 3.0
    2. 'F' > 'B' + 3
    3. -6 % 3 < 0
    4. (int)1.1 * 0.9 <= 0
    5. (2 + 3 < 6) == true
    6. (2 * 3 < 5) != true

  5. Because of the ways that Processing's floating point values are stored, it may happen that numbers which should, in theory, be equal are, in fact, only approximately equal. Thus, it is not a good idea to test for exact equality of two floating point values. A better idea is to see if the numbers differ by less than some desired value. For example, given two double values x and y, the expression

    abs(x - y) < abs(1e-3 * x) 
    will be true if and only if x and y differ by no more than l/1000th of the value of x.

    (a) Write an expression that will be true if and only if x and y differ by no more than one one-millionth of the value of x.
    (b) Why is it a good idea to have the test dependent on the magnitude of one of the values being compared?