3

I have an if statement followed by several else if statements. All of the if/else if statements have an argument structured something like this:

if (100 <= x <= 149) //do this
else if (150 <= x <= 199) //do that
else if ...etc...

However, for some reason only the first if statement ever gets executed. X can be 200 and only the first if statement will be recognized.

I'm not sure why it isn't moving on to the next else if statement when X doesn't fit the argument of the preceding statement. Does this not work in Obj-C? Any help is appreciated. Thanks

Chuck Norris
  • 15,207
  • 15
  • 92
  • 123
user339946
  • 5,961
  • 9
  • 52
  • 97
  • there are a lot of duplicates: [Language support for chained comparison operators (x < y < z)](https://stackoverflow.com/q/4090845/995714), [Why can't I just use 51 <= j <= 55? / data types (duplicate)](https://stackoverflow.com/q/54168808/995714), [100 <= x <= 150 as argument in if (), acting funny](https://stackoverflow.com/q/9014701/995714), [Is (val1 > val2 > val3) a valid comparison in C?](https://stackoverflow.com/q/38643022/995714)... – phuclv Dec 06 '19 at 06:25
  • Does this answer your question? [Language support for chained comparison operators (x < y < z)](https://stackoverflow.com/questions/4090845/language-support-for-chained-comparison-operators-x-y-z) – phuclv Dec 06 '19 at 06:26

8 Answers8

18

You need to rephrase the statements like:

if (x >= 100 && x <= 149) {
} else if (x >= 150 && x <= 199) {
} ...

Your first if is evaluated like:

if ((100 <= x) <= 149)

Let's have a look how that evaluates:

  • If x = 200, then (100 <= 200) is true and thus evaluates to the value 1 (which means true). And then 1 <= 149 is also true.
  • If x has a value smaller than 100, for example 10, then (100 <= 10) is false and thus evaluates to the value 0 (which means false). Again, 0 <= 149 is true.

So regardless of the value of x, the whole expression will always be true.

DarkDust
  • 90,870
  • 19
  • 190
  • 224
12

C is not math, so

if (100 <= x <= 149)

is NOT the same as

if (100 <= x &&  x <= 149)

Which is what you meant. The former will be true always, because 100 <= x <= 149 becomes

((100 <= x) <= 149)

leaving two possibilities: (1 <= 149) or (0 <= 149). Both are always true.

Dave
  • 10,964
  • 3
  • 32
  • 54
4

Chained comparisons like these don't work in C-based languages. Or rather, they do, but not how you'd expect.

100 <= x <= 149 gets evaluated as (100 <= x) <= 149. If x is over 100, then (100 <= x) will evaluate to true, or 1. If x is under 100, it's false, or 0. In either case, 0 <= 149 or 1 <= 149 is true, so the overall expression is true.

To fix this, change your conditions to look like this:

if (100 <= x && x <= 149) 

That will make it work as you expect.

BJ Homer
  • 48,806
  • 11
  • 116
  • 129
3

The compiler sees an expression formulated from binary operators. The <= symbol is a binary operator, as are =, >=, ||, &&, and so forth.

Just as with arithmetic, there is an order of precedence that the compiler must follow, evaluating the expression formed around each binary operator.

In arithmetic, you are probably familiar with this, as with these two examples:

2+5*7 This evaluates to 2+(5*7) or 37, because multiplication has precedence over addition.

2+3+21 is evaluated in the order the terms are read from left to right, since there is no other precedence rule. It becomes (2+3)+21.

So 100<=x<=150 is an expression of a similar type, where the binary operators are all the same, and thus have the same precedence. Once again, this is resolved by evaluating it from left to right, so it becomes (100<=x)<=150. If x>=100 the term in parentheses evaluates to TRUE, which has a numeric value of 1. Since 1 is less than 150, the rest evaluates to 1<=150, or TRUE, if x is greater than or equal to 100. On the other hand, it also evaluates to TRUE if x is less than 100, because the second comparison becomes 0<=150, which is TRUE.

The other recommendations to break this down with parentheses are correct if you aren't sure of the order of precedence for binary operators: (100<=x) && (x<=150). You can also write it as 100<=x && x<=150 since the order of precedence for value comparisons is higher than for logical operators.

Jim
  • 5,940
  • 9
  • 44
  • 91
2

Because if (100 <= x <= 149) is the same as if(1<=149) if you give 200 or another number to x. And that is correct always.

For example.

x=1

100<=1 is false so you get if(0<=149) which is true

x=200

100<=200 is true so you get if(1<=149) which is true

So you always get true for it.

So you must do it in another way, like this

if(x>=100 && x<=149) ...
Chuck Norris
  • 15,207
  • 15
  • 92
  • 123
  • Hi there, can you explain that a bit more? Why does it return as (1<=149)? How should I code my statements? – user339946 Jan 26 '12 at 06:41
2

Adding some additional parenthesis may help.

if ((100 <= x) && (x <= 149)) //do this
cdelargy
  • 56
  • 2
2

I don't think you can write math functions like this in objective-c... Try separating them and combining with an && statement:

if ( (100 <= x) && (x <= 149) ) { // "&&" = and, "||" = or, other math comparison operators are: <=, >=, <, >, ==, != (!= is does not equal))
//do this
} else if ( (150 <= x) && (x <= 199) ) {
//do that
} else if ...etc...
Albert Renshaw
  • 17,282
  • 18
  • 107
  • 195
  • Another method used if "&&" operators are too confusing is nested if statements, that's what I started on, but they are very sloppy in some cases. If they ARE ever required I would switch over to "switch" statements. Cheers! – Albert Renshaw Jan 28 '12 at 14:18
2

You've already got a lot of answers, but I'll add one more to cover one other possible point of confusion.

In C & Obj-C the boolean (and character) types are treated as integer types, which is not the case in call languages. So expressions like 'z' * true make perfect sense!

(Modern) C uses the type _Bool for boolean, which is defined to be large enough to hold 0 & 1. Cocoa uses the type BOOL for boolean, which is defined as signed char. CoreFoundation uses the type Boolean which is defined as unsigned char. All three define YES/true as 1 and NO/false as 0, while C itself treats any non-zero value as true.

The relation operators such as <, <= etc. are defined to return the int (yes, none of the booleans, not even _Bool) value 0 if the relation is false, and the int value 1 if the relation is true.

Given this and the left-to-right associativity of relational operators your:

if (100 <= x <= 149)

is parsed as:

if ((100 <= x) <= 149)

then 100 <= x evaluates to the int value 1 if x is greater than or equal to 100, otherwise it evaluates to the int value 0, so we get:

if (1 <= 149)

or

if (0 <= 149)

both of these evaluate to 1 so we get:

if (1)

and the if statement branches to the "then" branch if it's expression is non-zero.

It may be surprising, but the whole statement is evaluated without any use of booleans at all - it is all done with integers.

To achieve what you intended you need:

if((100 <= x) && (x <= 149))

etc. - which also doesn't use any booleans (&& is defined in terms of integers).

CRD
  • 52,522
  • 5
  • 70
  • 86