2

I am completely perplexed. We came across a bug, which we easily fixed, but we are perplexed as to why the value the bug was generating created the output it did. Specifically:

Why does ~True equal -2 in python?

~True 
>> -2 

Shouldn't the bitwise operator ~ only return binary?

(Python v3.8)

WolVes
  • 1,286
  • 2
  • 19
  • 39

2 Answers2

6

True is a specialization of int. In python, integers are signed and unbounded. If one were to invert a fixed-size integer like the 16 bit 0x0001, you'd get 0xfffe which is -2 signed. But python needs a different definition of that operation because it is not size bounded. In Unary arithmetic and bitwise operations python defines unary inversion as

The unary ~ (invert) operator yields the bitwise inversion of its integer argument. The bitwise inversion of x is defined as -(x+1). It only applies to integral numbers or to custom objects that override the invert() special method.

This has the same effect as fixed-size bit inversion without messing around with infinity. Sure enough

>>> -(True+1)
-2
tdelaney
  • 73,364
  • 6
  • 83
  • 116
0

Shouldn't the bitwise operator ~ only return binary?

Well, technically EVERYTHING in a computer is binary. However, this is only part of the story. There are two important concepts here:

  1. Data types of values
  2. Representations of those values

For the first one True is a boolean and -2 is an integer. In some cases, Python will convert a value from one type to another in order to perform certain operations. In this case, the ~ is the bitwise operator which only works on integers. In this case, an actual conversion isn't necessary since boolean inherits from int, so the boolean value can just be treated as the integer value of 1. Then ~ gives the bitwise inverse of that integer value.

Now if we represent the 1 in binary as 00000001 (yes, technically there are more 0s, but I'm not going to type them out...the concept still holds if we only use 8 bits instead of the actual 32 or 64), we negate this to 11111110 (again, there are more leading 1s because there are really more bits). Note that the way I write the integer value here in binary is merely a representation of the value using characters I can type on a keyboard. This is still 00000001 in binary and 1 in decimal both represent the same underlying value in memory. Similarly 11111110 binary and -2 decimal both represent the same value.

At the end, print() will just print the value in decimal which is why you get -2. If you want to print the value in hex or binary, there are built in methods to get these representations instead.

Code-Apprentice
  • 81,660
  • 23
  • 145
  • 268