You are on page 1of 14

Computers and their logic

• Have you noticed that the conditions we’ve used so far


have been very simple, not to say – quite primitive? The
conditions we use in real life are much more complex. Let's
look at the sentence:
If we have some free time, and the weather is good, we
will go for a walk.
We’ve used the conjunction “and”, which means that going
for a walk depends on the simultaneous fulfillment of the
two conditions. In the language of logic, the connection of
conditions is called a conjunction. And now another
example:
If you are in the mall or I am in the mall, one of us will
buy a gift for Mom.
The appearance of the word “or” means that the purchase
depends on at least one of these conditions. In logic terms,
this is called a disjunction.
Therefore, the “C” language must have operators to build
conjunctions and disjunctions. Without them, the
expressive power of the language would be substantially
weakened. We call these logical operators.
• The logical conjunction
operator in the “C” language is
a digraph && (ampersand
ampersand).

This is a binary operator with a


priority lower than the
comparison operators. It
allows us to code complex
conditions without the use of
parentheses like this one →
Pride && Prejudice
• The result provided by
the && operator can be
determined on the basis of
the truth table. If we consider
the conjunction of:
left && right
the set of possible values of
arguments and corresponding
values of the conjunction
looks as follows →
To be || not to be
• The disjunction operator is the
digraph | | (bar bar). It’s a
binary operator with a lower
priority than && (just like “+”
compared to “*”).
Its truth table looks as follows

To be || not to be
• In addition, there’s another
operator that can be used to
construct conditions. It’s a
unary operator performing
a logical negation. Its operation
is simple: it turns true into false
and false into true. This
operator is written as a single
character ! (exclamation
mark) and its priority is very
high: the same as the increment
and decrement operators.
• Its truth table is truly simple →
Some logical expressions

Note that the following
conditions
are equivalent,
respectively →
Some logical expressions
• You may remember De Morgan's laws from school.
They say that:
The negation of a conjunction is the disjunction
of the negations.
The negation of a disjunction is the conjunction
of the negations.

Let's try to write the same thing using the “C”
language →
Note how the parentheses have been used to code
the expressions.
We should add that none of the previous two-
argument operators can be used in the
abbreviated form known as op=. This exception is
worth remembering.
How to deal with single bits
• Logical operators take their
arguments as a
whole, regardless of how many
bits they contain. The operators
are aware only of the value: 0
(when all the bits are reset)
means “false”; not 0 (when at
least one bit is set) means “true”.
The result of their operations is
one of the values: 0 or 1. This
means that the following snippet
will assign a value of 1 to
the j variable if i is not zero;
otherwise, it will be 0 (why?).
However, there are four operators that allow you to manipulate single
bits of data. We call them bitwise operators. They cover all the
operations we mentioned before in the logical context and one
additional operator. This is the xor (exclusive or) and is denoted as ^
(caret). Here are all of them:
& (ampersand) bitwise conjunction
| (bar) bitwise disjunction
~ (tilde) bitwise negation
^ (caret) bitwise exclusive or
Let's make it easier:
& requires exactly two “1s” to provide “1” as the result
| requires at least one “1” to provide “1” as the result
^ requires only one “1” to provide “1” as the result
~ (is one argument and) requires “0” to provide “1” as the result
But take note: arguments of these operators must be integers (int as
well as long, short or char); we must not use floats here.
The difference in the operation of the logical and bit operators is
important: the logical operators do not penetrate into the bit level of its
argument. They’re only interested in the final integer value.
Bitwise operators are stricter: they deal with every bit separately. If we
assume that the int variable occupies 32 bits, you can imagine the
bitwise operation as a 32-fold evaluation of the logical operator for
each pair of bits of the arguments. Obviously, this analogy is somewhat
imperfect, as in the real world all these 32 operations are performed at
the same time.
How to deal with single bits
• Let’s have a look at an example of the
difference in operation between logical
and bit operations. Let’s assume that the
following declaration has been
performed:

int i = 15, j = 22;

If we assume that the ints are stored
with 32 bits, the bitwise image of the
two variables will be as follows →
How to deal with single bits
• The declaration is given:

int log = i && j;

We’re dealing with a logical conjunction. Let’s


trace the course of the calculations. Both
variables i and j are not zeros so will be
deemed to represent “true”.
• If we look at the truth table for
the && operator, we can see that the result
will be “true” and that it’s an integer equal to
1. This means that the bitwise image of
the log variable is as follows →
• Now the bitwise operation – here it is:

int bit = i & j;

The & operator will operate with each pair of


corresponding bits separately, producing the
values of the relevant bits of the result.
Therefore, the result will be as follows →

These bits correspond to an integer value of 6.


How to deal with single bits
• Let's try the negation operators now. First the logical one:

int logneg = !i;

The logneg variable will be set to 0 so its image will consist of


zeros only.
The bitwise negation goes here:

int bitneg = ~i;

It may be somewhat surprising that the bitneg variable value is


-16. Strange? Not at all! If you’re surprised, we hope it’ll be an
incentive for you to immerse yourself in the secrets of the
binary numeral system and the rules governing two's
complement numbers.
• Each of the previous two-
argument operators can be
used in
their abbreviated forms. The
following notations are
equivalent, respec vely →

You might also like