Operations between boolean variables
The previous time, we talked extensively about Boolean variables, trying to outline the main operations that can be carried out at a practical level.
Of all the cases examined, we have not examined the most important and most recurrent one: the case in which the conditions to be examined are more than one and, above all, when there is some relationship between them.
To resolve these situations, George Boole in 1847 invented a type of algebra commonly called Boolean algebra. In literature, Boolean algebra is defined as algebra in which the values, called truth values, can only assume "true" or "false" values, denoted with 1 and 0 respectively. It can be immediately noted that the "protagonist" entities of Boolean algebra are those we have defined as Boolean variables.
Boolean operators
As in traditional algebra, also in Boolean algebra it was necessary to define operators in order to carry out the operations between values of truth.
Before beginning the examination of the three fundamental operators, a new term should be introduced. Let us define as joint each member of a logical expression.
And - logical product
The first operation we examine is that of the logical product.
The situation is one in which we want to check that two or more conditions are true at the same time. We therefore want to verify that a series of conditions have occurred. The operator and will then return true if all the relatives of the condition are true at the same time.
The behaviour of a logical operator can be summarized through a double entry table. So let's see how the and operator behaves with two variables.
| A | B | A and B |
| true | true | true |
| true | false | false |
| false | true | false |
| false | false | false |
From this table you can see the behaviour mentioned above. The result of the and between two variables is true if and only if both relatives have the true truth value.
The and operator also has several properties. Below I'll list only those that are useful and essential for developing working code:
- commutative: A and B = B and A. Banally, it means that the order in which we execute the logical conjunction (alternative way of calling the and) is irrelevant;
- associative: A and (B and C) = (A and B) and C. This property tells us that whatever way we carry out a series of conjunctions, the result will always be equivalent.
The syntax in Java useful to express this operator is as follows:
condition1 && condition2 && ... && conditionn
So we see that in Java, the operator and can be expressed as follows: &&.
Let's see a simple example
int a = 5;
int b = 7;
if(a > 3 && b < 10){
...
}
In this particular case, we have two relatives that are a > 3 and b < 10. Evaluating them separately we obtain that both are true. We then get an expression of the true and true type, which returns true.
OR operator - logical sum
The second fundamental operator of Boolean algebra is the operator or, also called logical sum or logical disjunction.
The logical disjunction returns the true value if and only if at least one of the relatives is true. Therefore, in the moment in which we have to evaluate a condition of the type condition1 or condition2 or ... or conditionN, the result will be true if and only if at least one of the conditions is true.
Let's analyse the operator's truth table.
| A | B | A or B |
| true | true | true |
| true | false | true |
| false | true | true |
| false | false | false |
From this table we can see that what was said before is true. The logical disjunction of two or more operands is true if and only if at least one of the conjoined is true.
Just as the and, also the or has some properties that can be useful for development purposes. Let's see a couple of them:
- commutative: this property is similar to that of the logical product. It tells us that A or B = B or A.
- associative: it tells us that A or (B or C) = (A or B) or C. Wanting to read it with a natural language, it tells us that we can associate the conjoined in any way and make the disjunctions, obtaining an equivalent result.
This operator can be expressed by the following operator: ||.
Let's see an example similar to the previous one.
int a = 5;
int b = 7;
if(a > b || b < 10){
...
}
In this case, the assessment of the condition returns true, despite the fact that one of the two relatives is false. In fact, a is not greater than b. In spite of this, the second joint is true, therefore all the disjunction is true, since it is referable to an expression of the type false or true, which returns true.
Operator NOT - logical negation
This is the last basic operator and is the only one we have somehow already seen. The operator not, basically, acts as an inverter. When it has true input, it returns false and vice versa.
Let's see the truth table of logical negation.
| A | NOT A |
| true | false |
| false | true |
Now we can finally understand the notation given last time, which for your convenience I report below.
But first we need to know the syntax to use to express the operator not. Well, we have already seen this syntax, which uses the operator! (exclamation mark).
int a = 5;
boolean condition = a < 3;
if(!condition){
...
}
We can finally understand the meaning of what has been written. The if condition will be translated as
if(!false)
From the table given before, you can see that !false = true. We then get a code like
if(true)
which is a valid and working writing.
Lazy evaluation order
We have introduced the three main logical operators. To conclude this first overview, it is good to introduce one last concept, which is the lazy evaluation order.
This means that, when one and/or are evaluated, a technique is used such that the number of relatives evaluated is the minimum. Let's take a closer look:
lazy evaluation of the logical conjunction: the logical product (and) is evaluated until the examined conjunction is true. When a false joint is found, the evaluation of the whole condition is interrupted.
lazy assessment of logical disjunction: the logical disjunction (or) is assessed until a true joint is found. When a true relative is found, the assessment is discontinued and the entire condition is assessed as true.
- lazy evaluation of the logical conjunction: the logical product (and) is evaluated until the examined conjoineds are true. When a false joint is found, the evaluation of the whole condition is interrupted.
- lazy evaluation of logical disjunction: the logical disjunction (or) is assessed until a true joint is found. When a true relative is found, the assessment is discontinued and the entire condition is assessed as true.
This makes us understand that, when we have many conditions in and between them, it is good to write at the beginning those that are more likely to be false, so as to avoid long evaluations. On the contrary, with the disjunctions, it is preferable to write first the conditions that are more likely to be true.