Conditionals - The true or false story

I have yet again seen a piece of code similar to the following very common mistake

1
2
3
4
5
6
if (chr == 'Y' || 'y') // this will always return true
  do_something; // and this will always be called
else if (chr == 'N' || 'n') // this makes same mistake as above
  do_something_else; // but, this will never be called because of above
else
  do_some_other_thing; // This will never be called 


Before I get into why that first if will always return true, let's look at a few details about how conditionals work.

What is a conditional?
A conditional is a statement that evaluates to true or false. All of your control structures rely on conditionals. This includes..

1
2
3
4
5
6
7
8
9
10
11
12
13
14
if ( conditional )
else if ( conditional )

while ( conditional )

do { ... }
  while ( conditional )

// even
for ( initialization; conditional; incremental)
// for loops can have an empty conditional which evaluates to true. But this only works for For loops.

// and there is the conditional operator
int a = conditional ? ... : ...;


And since conditionals evaluate to true or false then the above can also be writen as such..

1
2
3
4
5
6
7
8
9
10
11
if (true)
else if (true)

while (true)

do { ... }
  while (true)

for ( ...; true; ...)

int a = true ? ... : ...;


Naturally, if (true) would defeat the purpose of the if statement, but while (true) is very commonly used.

So how do we define True or False?
A lot of people would tell you that false is zero, and true is any number larger than zero. This is not entirely accurate. To be more percise, false is zero and true is any non-zero. This includes negative numbers. (I have tested to confirm this with DevC++)

False can also be null which is distinctly different from zero. There are many functions that return null, so this can also be used as a conditional.

So what qualifies as a conditional?
Anything that evaluates to true or false. All of your comparisons, such as greater than '>', less than or equal to '<=', and is equal to '==' evaluate to true or false.

1
2
3
4
5
6
7
8
9
10
11
12
int i = 5; // integer i is equal to five.

if (i == 5) // this evaluates to
if (true)

else if (i < 5) // this evaluates to
else if (false)

while (i >= 5) // this evaluates to
while (true)

// and so forth 


All of your assignments also evaluate to true or false. This is because assignments also return a value. a = 5; stores the number 5 into the variable a. But it also returns the value 5. This is why b = a = 5; works. It first stores 5 into a, then returns 5 which is stored into b.

The b = 5; also returns 5, but since we don't store it into anything else, it gets lost into time and space, never to be seen again. This is ok, since someday someone will invent a hyperspace engine that gets its power from all of these lost values floating around.

1
2
3
4
5
6
7
8
// notice one '=' sign makes it an assignment, not a comparison
if (a = 5) // this evaluates into
if (5) // which since 5 is a non-zero, it evaluates into
if (true)

if (a = 0) // this evaluates to
if (0) // which as we know from above evaluates to
if (false)


Then finally, there are many functions that you can call that return values. Any function that does not return a void (or by definition of void does not return anything) can be used as or in conditionals.

Logical Operators
There are two logical operators that can be used to concatenate conditionals. These are the And '&&', and the Or '||' operators. both of these take two conditionals, one on either side, and evaluate each conditional seperately.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
if ( condition_1 || condition_2 ) // or
if ( condition_1 && condition_2 ) // and

int i = 5, j = 1;

if ( i == 3 || j == 1 ) // evaluates to
if ( false || true ) // evaluates to
if ( true )

if ( i == 5 && j == 3 ) // evaluates to
if ( true && false ) // evaluates to
if ( false )

// You can even use multiple concatenations.
int h = 3;

if ( i == 2 || ( j == 1 && h == 3 ) ) // evaluates to
if ( false || ( true && true ) ) // evaluates to
if ( false || true ) // evaluates to
if ( true )


And this brings us back to the code at the beginning, and why it will always return true. That code reads...

1
2
3
4
if (chr == 'Y' || 'y') // which if chr = anything other than 'Y' would evaluate to
if ( false || 'y' ) // and since 'y' is a non-zero this would evaluate to
if ( false || true ) // which will evaluate to
if ( true )


Special Note
You can also use assignments and function calls with the logical operators. However, special care should be given here, as doing so may have unexpected results. This is due to the way the program handles these logical operators.

For example, Or returns true if either conditional is true. It checks the first conditional, and if it returns false, it will check the second conditional. If, however, the first conditional returns true, it does not need to check the second conditional. It already has enough information to return true. Let's take the following code for example..

1
2
3
4
5
6
7
8
9
10
11
12
   int i = 0, j = 0;
   while (true)
   {
      if (++i >= 5 || ++j >= 5) // OR
         cout << i << " " << j << " true" << endl;

      else
         cout << i << " " << j << " false" << endl;

      if (i >= 10)
         break;
   }


One would think from looking at this code that both i and j would reach 10. However, once i reaches 5, it returns true and thus the second conditional no longer needs to be tested. The result is the following output.

1 1 false
2 2 false
3 3 false
4 4 false
5 4 true
6 4 true
7 4 true
8 4 true
9 4 true
10 4 true


And, however, requires both conditionals to be true. So it checks the first conditional, and if it returns true, it will check the second conditional. If, however, the first conditional returns false, there is no reason to check the second conditional. It already has enough information to return false. Thus the following code..

1
2
3
4
5
6
7
8
9
10
11
12
   int i = 0, j = 0;
   while (true)
   {
      if (++i >= 5 && ++j >= 5) // AND
         cout << i << " " << j << " true" << endl;

      else
         cout << i << " " << j << " false" << endl;

      if (i >= 10)
         break;
   }


.. produces the following output..

1 0 false
2 0 false
3 0 false
4 0 false
5 1 false
6 2 false
7 3 false
8 4 false
9 5 true
10 6 true


The Not Operator
And there is of course, one more logical operator to consider. the Not '!' operator which when put in front of the conditional, simply reverses it. It turns true into false and false into true.

1
2
3
4
5
6
7
if (!true) // evaluates to
if (false)

// and

if (!false) // evaluates to
if (true)


Side Note: XOR
I originally had Xor as a logical operator, but it is not. It is a bitwise operator. It is possible, however, to emulate the Xor functionality in a logical sence. Xor is simply 'Or And Not And'. However, using assignments in part or all of this is much more difficult to predict the possible outcomes.

1
2
3
4
5
6
7
8
9
10
11
12
   int i = 0, j = 0;
   while (true)
   {
      if ((++i >= 5 || ++j >= 5) && !(++i >= 5 && ++j >= 5))
         cout << i << " " << j << " true" << endl;

      else
         cout << i << " " << j << " false" << endl;

      if (i >= 10)
         break;
   }


..produces this output..

1 1 false
2 2 false
3 3 false
4 4 false
6 5 false
8 6 false
10 7 false
Last edited on
(thanks to whoever moved it back to articles for me.)

Anyone see anything that needs corrected or added to the above? Anything that may make any of the above more clear to the readers?
Last edited on
Perhaps discussion on concatenating conditions; like
if(h == 5 || (i == 5 && j == 5) )
, or using the conditional operator; like
h == 5? 7 : 6;
but overall, purty good.
the conditional operator
h = 5 ? 7 : 6;

was sort of outside of my scope here, but i'll look into it.

As for the concatenating conditionals such as
if (h == 5 || (i == 5 && j == 5) )
is something i should add in, i was thinking of going a bit further with my examples showing how
if (i >= 5) evaluates to if (false) and if (true)
Then showing how
if (i >= 5 || if j >= 5) evaluates to if (false || true) wich evaluates to if (true)

If i did that, then going the next step and having
if (h == 5 || (i >= 5 && j >= 5) ) evaluates to
if (h == 5 || (true && true) ) evaluates to
if (false || true) evaluates to
if (true)

but i was woried i might confuse some people with that.
Last edited on
Ok, updated. Looks a bit better. Gives examples. Had some trouble with notepad putting in random line breaks, but turning off word wrap (after having written it) fixed that problem. Changing title to remove the [Draft] part. anyone else have any suggestions?

sorry, made a few corrections to the main article and added something else, to the end.
Last edited on
closed account (z05DSL3A)
There is a small...

The XOR [^] operator is a bitwise operator, not a logical operators. Using it in a Logical context could produce an unexpected result.

For an example, if you had a couple of functions that returned zero for failure and non-zero for success and you XORed the returned value, both can return success (true) but with different values, but the XOR would return true instead of false, because it is doing a bitwise comparison.

1
2
3
4
5
6
7
8
9
#include <iostream>

int main()
{
    std::cout << ((2 ^ 2)? "true" :"false") << std::endl;
    std::cout << ((2 ^ 3)? "true" :"false") << std::endl;

    return 0;
}


Last edited on
ok.. odd. for some reason I could have sworn when I looked that up originally that it was grouped with the logical operators. It's on the same page, but as I just looked, further down on the page, with the bitwise.

I was seeing things. heh. So there is no Logical XOR? only the bitwise XOR?
hrm.. there is a way to do it, but not in the context of what I have up above. XOR is simply 'Or and Not And' wich is:
((a || b) && ! (a && b))

but if you tried to use ++a and ++b in all or even part of that, it could get very confusing what the results will be.

Ok.. corrected. Thanks Greywolf
Last edited on
There actually is a logical xor operator, however most people know it as 'not equal'.
If you compare the 4 combinations of true and false for logical xor and != you will see they give the same results.
You must be careful though, since != will not convert the values to booleans first. So if(conditionA != conditionB) will work, but if(valueA != valueB) may not. You can get around this by typecasting to bool before comparing.
Logical operations != Bitwise operations

Be careful on what assumptions you make.

0100 --> true true
xor 0010 --> true != true
-------- --------
0110 --> true false

A logical xor is basically this:

1
2
//assuming two bools, L/R
(L || R) && (!(L && R))


Although there actually ISN'T one, the only logical operators are:

AND &
OR v
NOT ~
IF_THEN <horseshose symbol>
IF AND ONLY IF <triple bar symbol>
Last edited on
Er, actually there are a couple more.

∧ conjunction
http://en.wikipedia.org/wiki/Logical_conjunction
⋁ disjunction
http://en.wikipedia.org/wiki/Logical_disjunction
¬ negation
http://en.wikipedia.org/wiki/Logical_negation
→ implication
http://en.wikipedia.org/wiki/Logical_implication
↔ bi-implication
http://en.wikipedia.org/wiki/Bi-implication
∀ universal quantifier
http://en.wikipedia.org/wiki/Universal_quantifier
∃ existential quantifier
http://en.wikipedia.org/wiki/Existential_quantifier
Alas, there are a lot of variations on the actual symbols used for logical operators. The ones I listed are the classical set (used in predicate calculus, aka first-order logic). The Wikipedia links lists others.

The one to watch out for is ≡, which is often seen in congruence relations, for example 11 ≡ 5 (mod 2) hence 11 ≡ 2 (mod 5). This is a branch of mathematics unrelated to predicate calculus.

Others exist either to accomodate computers or to distinguish problem domain and/or application.

Programming languages lend themselves to predicate calculus. A predicate is essentially a boolean function. Mathematically, I can give the example:

Bx
means 'x' is a bird
Tt
means 't' is a tree
Hxt
means that the bird 'x' is lives in the tree 't'
I can construct logical sentences thus:

Bx → ¬Tx
if 'x' is a bird then 'x' cannot be a tree (a true statement)
¬Tx → Bx
if 'x' is not a tree then 'x' must be a bird (a false statement)
hence

Bx ↔ ¬Tx
'x' must be either a bird or a tree (again false)
The reason goes straight to the truth tables learnt in high-school. Check out http://en.wikipedia.org/wiki/Truth_table for more.

Also play with google some for more fun. :-)

Enjoy!

[edit] Heh, forgot to use H.

∀x(Bx → ∃t(Hxt))

Remember N(x) is a predicate. See if you can decipher this sentence and determine whether it is true or false. :-)
Last edited on
Topic archived. No new replies allowed.