-3

I want the step by step explanation of the following code:

print(1 | 0 ^ 1 & ~0)

I tried with the output bit (output with first and second bit) and got the answer as 0. The tilde function got me hooked up for some time I found it a bit hard. The answer is 1.

alex
  • 10,900
  • 15
  • 70
  • 100
  • Make sure you understand the precedence of the various operators which are described here:- https://docs.python.org/3/library/operator.html – DarkKnight Oct 27 '22 at 14:10
  • I would appreciate if you selected an answer since I and another contributor have sufficiently answered the question. – James Newman Oct 27 '22 at 17:38

2 Answers2

2

First you must understand what each operator does

| - Bitwise OR: Returns True (1) if either of its operands is 1. e.g.

1 | 0 == True

& - Bitwise AND: Returns True if both of its operands are 1. e.g.

0 & 1 == False

^ - Bitwise XOR: Returns True if only one of its operands is 1. e.g.

0 ^ 1 == True

~ - Bitwise NOT: Flips the bit of its operand.

edit: As noted by Daniel Martin, In Python specifically, it flips all of the bits of an arbitrary integer. The formula would be ~x == -x - 1 e.g.

~0 == -1

Then you must understand the order of bitwise operations

In order of precedence:

~ -> & -> ^ -> |

Solving the expression in that order

  1. 1 | 0 ^ 1 & ~0 == 1 | 0 ^ 1 & -1 - ~ is applied first
  2. 1 | 0 ^ 1 & -1 == 1 | 0 ^ 1 - & is applied second
  3. 1 | 0 ^ 1 == 1 | 1 - ^ is applied third
  4. 1 | 1 == 1 - | is applied last
James Newman
  • 110
  • 8
  • Except that `~0` is in python `-1`, because it flips "all" the bits, whatever that means for an arbitrary-sized integer. – Daniel Martin Oct 27 '22 at 14:22
  • @James Newman Thanks for the explanation. I have one more doubt so does the bitwise operators binding is from right to left then? –  Oct 27 '22 at 14:31
  • @JayantAgarwal The official documentation for the order of operations in python expressions is https://docs.python.org/3/reference/expressions.html , but among bitwise operators it's: first `~`, then `<<` and `>>` (left to right), then `&`, then `^`, then `|`. – Daniel Martin Oct 27 '22 at 15:07
  • @JayantAgarwal It does not read right to left. It's just like regular math where the precedence of certain operators are higher than others. `2 + 3 * 2` for example is read as `2 + (3 * 2)` since the `*` operator has a higher precedence than `+`. You _effectively_ start from the right, but that's just because the rightmost statement `3 * 2` has higher precedence and happens to be on the right. – James Newman Oct 27 '22 at 17:36
1

Okay, first let's put some parentheses in that code to show how the order of operations applies in python:

print(1 | 0 ^ 1 & ~0)

becomes

print(1 | (0 ^ (1 & (~0))))

Okay, all good.

Now then, first we'll go through what ~0 means, then we'll consider what 1 & (~0) is, then 0 ^ (1 & (~0)), then 1 | (0 ^ (1 & (~0))).

Because these are all bitwise operations, I'm going to flip back and forth between decimal and binary without warning. I hope you've had a basic introduction to what binary is.

So, first ~0. In languages with integer types that have a specific width, (e.g. in C or C++) ~0 would mean "a value that in binary is all 1 bits, as wide as the type", since ~ means "flip all the bits" and 0 is represented with all bits 0. But since python's integers don't have a specific width that would mean "a value that in binary is an infinite sequence of 1 bits", and so we have to fall back on what it says in the documentation:

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.

So ~0 is -1.

Now, what's 1 & (-1) ? Well, in binary 1 is just 1, and -1 is all 1 bits, as large as you might want. So the bitwise & of those two values is just 1, since for bitwise & the output has a 1 bit only where both inputs have a 1 bit.

Now, 0 ^ (1). Well, we know what 0 looks like in binary, and we know what 1 looks like in binary (they look just like decimal), and with ^ the output has a 1 bit only where the output and input differ. So 0 ^ 1 is just 1.

Now 1 | (1). This is just 1, by the definition of |.

In a way, python makes reasoning this out harder than it would be in C or many other languages by not having a fixed size for its integers, so when dealing with ~0 you have to briefly imagine that there's this infinite string of 1s that you're dealing with, but it isn't that bad.

Daniel Martin
  • 23,083
  • 6
  • 50
  • 70