The last example can be written in an alternative form which improves the readability:
This says “fall through if correct is less than 5, otherwise jump to done”. The condition (correct<5) we call a “logical expression” because it has only two possible values, “true” (-1) or “false” (0), whereas numerical expressions can have any numerical value. Since a logical expression can have only two values (-1 if true, or 0 if false) it is pointless to list more than two unit names after the condition.
Actually, because of rounding, the form “jump N<5,x,done” is more precise than the form “jump N-5,x,done”. Suppose that N is 4.8. Then “N<5” is true (-1), which rounds to -1, which implies “x”. But “N-5” is -0.2, which rounds to zero, which implies “done”. Such differences appear whenever you have variables which can have noninteger values.
Here is another example:
The above will do unit “near” if c and b differ by no more than 0.5, since (in that case) “c-b” will lie between -0.5 and +0.5, which rounds to zero. On the other hand:
will do unit “same” only if c and b are equal. The condition “c=b” is true (-1) only if c is equal to b.
There are six basic logical operators: =, ≠, <, >, ≤, and ≥ which mean equal, not equal, less than, greater than, less than or equal, and reater than or equal. The statement “do a≠b,diff,same” is equivalent to “do a=b,same,diff”. These comparison operators consider two numbers to be equal if they differ by less than one part in 1011 (relative tolerance) or by an absolute difference of 10-9, whichever is larger. This is done to compensate for small roundoff errors, inherent to computers, due to their very high but not infinite precision. One consequence is that all numbers within 10-9 of zero are considered equal by these logical operators. If it is necessary to test very small numbers, scale up the numbers: 1000a<1000b can be used if a and b are larger than 10-12 (since multiplying by 1000 brings the quantities up above the 10-9 threshold).
You can mix logical expressions with numerical expressions in many effective ways. For example:
gives “x⇐125” if y is greater than 13 (“y>13” if true is -1) or it gives “x⇐100” if y is less than or equal to 13 (“y>13” if false is 0). To clarify this, suppose that y is 18 or y is 4:
In these applications it would be nice if “true” were +1 rather than -1, but the much more common use of logical expressions in conditional branching commands dictates the choice of -1 (since the first unit listed is chosen if the condition is negative).
You can combine logical expressions. For example:
is: true (-1) only if both conditions (3<b) and (b<5) are true. In other words, b must lie between 3 and 5 for this expression to have the value -I. Similarly,
will be true if either (y>x) is true or (b=2) is true (or both are true).
Finally, you can “invert” the truth of an expression:
is true if is not true. This complete expression is equivalent to “b≠3c”.
The combining operations $and$, $or$, and “not” make sense only when used in association with logical expressions (which are -1 or 0). For instance, [b>c $and$ 19] is meaningless and will give unpredictable results. (If you have done a great deal of programming, you might wonder about special bit manipulations, but there are separate operators for masking, union, and shift operations, as discussed in Chapter 10.)