3

I wanted to make a simple comparison using h == 1 | 2 where h could be an integer between 1 and 4. To my astonishment, it didn't work.

I could sort of understand why

1 == 2 | 4

TRUE

and perhaps even why

1 == (2 | 4)

TRUE

but why in the name of all that's reasonable and sane does

as.numeric(1) == (2 | 4)

or

1L == (2 | 4)

or

3 == 2 | 4

evaluate to

TRUE

???

How can I ask R to tell me whether 1 is equal to 2 or 4 and the answer will be FALSE?

Community
  • 1
  • 1
Harold Cavendish
  • 869
  • 10
  • 22
  • 6
    you shoud use `1 %in% c(2,4)` – dww Jun 03 '18 at 23:14
  • 2
    What do you expect `2|4` to evaluate to? – Hong Ooi Jun 03 '18 at 23:26
  • @HongOoi I would expect behaviour like in Julia or JavaScript, certainly not coercion from numeric to logical… – Harold Cavendish Jun 03 '18 at 23:37
  • Please answer the question. 2|4 evaluates to TRUE even though ti's kind of a meaningless statement. @dww is more along the lines of what you want. Just testing 2|4 at the command line would have probably helped you understand the notation. – Elin Jun 03 '18 at 23:58
  • 2
    by the way, in Julia and python `1 == 2|4` is `false`, but not for the reason you think: `|` is the bitwise or operator, so `2|4` evaluates to 6 ... Not really worth an answer of its own, but maybe worth someone including in an existing answer ... – Ben Bolker Jun 04 '18 at 00:39

3 Answers3

7
1 == 2 | 4

Operator precedence tells us it is equivalent to (1 == 2) | 4

1 == 2 is FALSE, 4 is coerced to logical (because |is a logical operator), as.logical(4) is TRUE, so you have FALSE | TRUE, that's TRUE

Indeed coercion rules for logical operators (?Logic) tell us that:

Numeric and complex vectors will be coerced to logical values, with zero being false and all non-zero values being true.


3 == 2 | 4

Same thing


1 == (2 | 4)

2 | 4 will be coerced to TRUE | TRUE, which is TRUE. Then 1 == TRUE is coerced to 1 == 1 which is TRUE.

Indeed coercion rules for comparison operators (?Comparison) tell us that:

If the two arguments are atomic vectors of different types, one is coerced to the type of the other, the (decreasing) order of precedence being character, complex, numeric, integer, logical and raw.


as.numeric(1) == (2 | 4)

Same thing


1L == (2 | 4)

Same again


1 is equal to 2 or 4

is actually (1 is equal to 2) or (1 is equal to 4), which is:

(1==2)|(1==4)

which is

FALSE | FALSE

which is FALSE

moodymudskipper
  • 46,417
  • 11
  • 121
  • 167
  • Ahh, coercion… Thank you, I didn't realise something like `as.logical(4)` would be `TRUE`. I don't think that's reasonable at all. – Harold Cavendish Jun 03 '18 at 23:21
  • 2
    It's like this in most languages, 0 is nothing, 1 or 4 or 100 is something, so it's `TRUE`, it's useful in many circumstances. – moodymudskipper Jun 03 '18 at 23:22
  • but `3 == TRUE` is FALSE, while `3 == 2 | 4` is TRUE – SeGa Jun 03 '18 at 23:24
  • I think it would help a lot to parse the expression with `ast`: http://adv-r.had.co.nz/Expressions.html – MichaelChirico Jun 03 '18 at 23:40
  • 1
    Neither JavaScript nor Julia nor Python behave like this and I don't know much else. In any case, thank you for the detailed explanation. – Harold Cavendish Jun 03 '18 at 23:43
  • 2
    but `bool(4)` is true so python _does_ behave the same way. `bool(0)` is false and `bool(-1)` is also true – rawr Jun 03 '18 at 23:54
  • Not `?logic`, rather `?Logic` – IRTFM Jun 04 '18 at 00:03
  • yes, and not `?comparison` but `?Comparison`, corrected, thanks – moodymudskipper Jun 04 '18 at 00:04
  • Note that the "safe and reliable way to test two objects for being exactly equal" is to use `identical()` (see `?identical`) so `1 == TRUE` is `TRUE` but `identical(1,TRUE)` is `FALSE`. This is a way to make sure no coercion occurs. So for your question `identical(1,2)|identical(1,4) = FALSE` – Sarah Jun 04 '18 at 00:29
  • AFAIK Javascript also converts 0/Undefined/""/NaN to False and every other number, including Infinity, to True. So that also seems consistent with R's behaviour - https://stackoverflow.com/questions/45463109/javascript-type-conversion-table – thelatemail Jun 04 '18 at 00:54
4

Running 2|4 evaluates to TRUE. That is why you obtain TRUE when comparing 1 == TRUE. What you want to evaluate is (1 == 2) | (1 == 4), which results in the desired FALSE.

abu
  • 737
  • 5
  • 8
  • 19
3

The code that will deliver the expected answer to the implicit question in your first sentence is:

1 %in% 2:4
[1] FALSE

h=1
h %in% 1:2
[1] TRUE

The "==" operator does not implicitly generate a range (or a vector of alternatives) from a logical conjunction. It is considered a "Comparison"-operator and is "generic" which will mean that methods can be different for different data-types. They are also vectorized (with the implicit recycling rules in force) so may return many values:

(1:2) == (1:4)
[1]  TRUE  TRUE FALSE FALSE

And the as.numeric()-function applied to the value 1 will return exactly the input.

Further comment: Since your attempted use of "==" was really as an implicit set operation, you might want to review the help page for ?intersect. There're also packages that handle more sophisticated set functions.

R's coercion can go back and forth between logical and numeric depending on how functions are defined:

sum( letters[1:10] %in% letters)
[1] 10

sum( letters[1:10] == letters)
[1] 10
Warning message:
In letters[1:10] == letters :
  longer object length is not a multiple of shorter object length
IRTFM
  • 258,963
  • 21
  • 364
  • 487
  • I was looking for c(2, 4) rather than 2:4, but thanks, this is also useful. – Harold Cavendish Jun 03 '18 at 23:50
  • Same difference, really. `1 %in% c(2,)` is likewise FALSE. Python's `or`-function handles numeric values in a bitwise binary fashion so `2 or 3` returns `2`. I would dispute any claim that this is more "intuitive" than what R returns. Both are useful in exactly the same setting... their use by someone who has taken the time to read the definitions of the operators and datatypes. – IRTFM Jun 03 '18 at 23:56