Search code examples
c++if-statementcomparison-operators

if statements and relational and comparison operators: "Exceptions" When comparing three values/variables


Context

Taking a c++ course and if statements and relational and comparison operators came up. I don't know enough c++ vocabulary so I apologize if this question has been asked before. I tried searching around, but I didn't find anything.

Problem

Below illustrates an example of what I am confused about.

int n = 1;

if(2 < n <1){
    cout << n << endl;
}

When the program is ran, the cout statement gets printed to the console (which is surprising to me).

Question

How is C++ interpreting the values and relational and comparison operators within the if statement?

If there are any other interesting "exceptions" like this documented somewhere could you please reference it for me, thank you.

Ans Attempt

I'm not totally sure what is going on. To me it seems like the middle number is getting skipped?

After playing with the numbers a few times I've now been able to confirm that the middle number is getting skipped, but I have no idea why.

If I add arguments by scaling the problem up:

if(2 < n < 0 <1){
    cout << n << endl;
}

and also:

if(2 < n < 1 < 1 < 1){
    cout << n << endl;
}

Now I get really confused. It seems like whatever "thing" is in the middle gets ignored. But I found an exception to my pattern when n = 3 causes the if statement to be "false":

int n = 3 
if(2 < n < 1 < 1 <1){
    cout << n << endl;
}

But then if I change n to what seems like "any" (not exhaustive) other number the if statement will yield true again.


Solution

  • The 2 < n < 1 ain't does what you think it should:

    Because these operators group left-to-right, the expression a<b<c is parsed (a<b)<c, and not a<(b<c) or (a<b)&&(b<c) - cppreference.com

    The 2 < n part will return a Boolean value which in turn will be compared in the < 1.

    2 < n < 1;
    // equal to 
    (2 < n) < 1;
    

    So, in total, the 2 < n < 1 flows like so:

    • (2 < n) < 1. Is n greater than 2? No, return false.
    • false < 1. The false is promoted to an integer, to 0. Is 0 less than 1? Yes, the if condition is true.

    That's why when n == 3 in the 2 < n < 1 < 1 < 1, the overall you get false:

    • (2 < 3) < 1 < 1 < 1. Is 3 greater than 2? Yes! Returns 1 (true)
    • (1 < 1) < 1 < 1. Is 1 less than 1? No! Return 0 (false)
    • (0 < 1) < 1. Is 0 less than 1? Yes! Return 1 (true)
    • 1 < 1. Is 1 less than 1? No! Return 0 (false)

    It is nonsensical as you can see. In order to make it work, you will have to make explicit checks:

    (n < 2) && (n > 1)
    // is n less than 2 AND is n greater than 1