2

I'm terribly sorry if this is below-standard question, but I couldn't find clear answers.

As the title says, why does True and (~True) give -2 while True&(~True) gives 0? Also, Why do both of them not give False?

This is very counter-intuitive, since I expect for a single boolean expression & and and should work in the same way.

Hojin Cho
  • 354
  • 1
  • 9

2 Answers2

8

True has a value of 1 in Python. Bit-inverting (~) a binary 1 (...0001) gives you ...1110. Since negative integers are represented by two's compliment, that's a value of -2.

Logical and returns its left operand if it's false, the right operand otherwise. (True is never false, obviously.)

Bitwise &, on the other hand, works on the individual bits. ...0001 & ...1110 have no 1 bits in the same position so they're all zeros in the result.


I was just surprised that a numpy array with dtype=bool acts differently with literal bool

Each Python type can implement an operator's methods with special method names. (Like .__invert__() for ~). But and, or, and not don't have these hooks, so often &, |, and ~ are used instead. For ints the implementation is bitwise, but other types can interpret operators however they want.

Note that bool is a subclass of int in Python, so it has the same operators as int. But you were operating on a numpy.ndarray, not on its individual components, so Python uses the ndarray implementation of the operators, which are not the same as bool when dtype=bool.

gilch
  • 9,664
  • 1
  • 21
  • 28
  • This is certainly not what I expected, especially considering that I deal with large numpy arrays and use `~` to negate anything, since `not` does not work on boolean arrays. Thank you for the detailed explanations. – Hojin Cho Nov 10 '20 at 08:25
  • https://numpy.org/doc/stable/reference/generated/numpy.logical_not.html – gilch Nov 10 '20 at 08:27
  • I know about it, but that's too wordy (thus leads to typos) when I write a long scripts, so I did not use it that often, and I don't think I'll use it a lot even after this fiasco... Or should I? I think it works exactly the same as `~` – Hojin Cho Nov 10 '20 at 08:38
  • Not if dtype is int. – gilch Nov 10 '20 at 08:47
  • Indeed, but I usually assign types very strictly so that's not something I'd encounter often. I was just surprised that a numpy array with `dtype=bool` acts differently with literal `bool`. – Hojin Cho Nov 10 '20 at 08:52
  • 1
    Each Python type can implement an operator's methods with [special method names](https://docs.python.org/3/reference/datamodel.html#special-method-names). (Like `.__invert__()` for `~`). But `and`, `or`, and `not` don't have these hooks, so often `&`, `|`, and `~` are used instead. For ints the implementation is bitwise, but other types can interpret operators however they want. – gilch Nov 10 '20 at 08:59
3

Remember, True == 1 and False == 0.

So,

True and (~True)

Is the same as

1 and (~1)

~ is a bitwise operation. Which kind of inverts the binary of 1. If we

print(~1)

-2

So the whole thing is simplified into

1 and -2

Which is just -2


& vs and

I expect for a single boolean expression & and and should in the same way

Dont! and is a boolean test. & Is a bitwise operation. Both of them are very different.

  • Thank you very much for the detailed explanations. I assumed somehow a `bool` type literally has, one bit. – Hojin Cho Nov 10 '20 at 08:27
  • @interjay That's right, its best not to use `&` where `and` belongs :) –  Nov 10 '20 at 08:34