Search code examples
pythonconditional-statementsbitwise-operators

Bitwise operator & in Python


Recently I was solving one of the very basic problems on conditionals from Hackerrank.

The problem was:

If n is odd, print Weird
If n is even and in the inclusive range of 2 to 5 print Not Weird
If n is even and in the inclusive range of 6 to 20 print Weird
If n is even and greater than 20, print Not Weird

So i wrote the following code

if(n % 2 == 0 & n >=6 & n <= 20 ):
    print("Weird")
elif(n % 2 == 0 & n <= 2 & n >= 5): 
     print("Not Weird")
elif( n % 2 != 0):
     print("Weird")
else:
     print("Not Weird")

It didn't work at first. I figured out that i had to use "and" instead of "&".
But, I am not convinced why did this happen..
for n = 12, all 3 conditions of the first if condition are true. so true & true & true should also be true, right?

this photo shows the code snippet with some print messages

I am very intrigued to know the reason behind this behaviour, please guide! (may be something very minor but please don't mind :) )


Solution

  • Every time you have this kind of doubts, you can use the dis module, in your case I make a lambda function to evaluate the process:

    func = lambda x: x % 2 == 0 & x >= 6 & x <= 20
    

    this gives us the follow disassmbled code:

                  0 LOAD_FAST                0 (x)
                  2 LOAD_CONST               1 (2)
                  4 BINARY_MODULO
                  6 LOAD_CONST               2 (0)
                  8 LOAD_FAST                0 (x)
                 10 BINARY_AND
                 12 DUP_TOP
                 14 ROT_THREE
                 16 COMPARE_OP               2 (==)
                 18 JUMP_IF_FALSE_OR_POP    40
                 20 LOAD_CONST               3 (6)
                 22 LOAD_FAST                0 (x)
                 24 BINARY_AND
                 26 DUP_TOP
                 28 ROT_THREE
                 30 COMPARE_OP               5 (>=)
                 32 JUMP_IF_FALSE_OR_POP    40
                 34 LOAD_CONST               4 (20)
                 36 COMPARE_OP               1 (<=)
                 38 RETURN_VALUE
            >>   40 ROT_TWO
                 42 POP_TOP
                 44 RETURN_VALUE
    

    explained is just:

    • Get var x value
    • Get const 2 value
    • Get modulo comparison between 2 and x, the answer is 0 when you use 12 as the param value.
    • Get const 0 value
    • Get var x value
    • Get Binary and comparison between 0 and x, naturally, a bitwise operation between any value (eg: b'1100') and b'0000' will return 0.
    • Next, values are stored in TOP and compared with == operator. This means as other answers said (x % 2) == (0 & x) at this time, with x being 12, the translated operation is 0 == 0 (True).
    • With the == result check if is False (in that case, jump to row 40 of bytecode) else, remove the result (POP) from TOS (Top of stack)
    • Get const 6 value
    • Get var x value
    • Another and comparison, this time between 6 (b'0110') and 12 (x = b'1100') with a result of 4 (b'0100')
    • The last result is stored in TOP and compared with >= operator with the last stored value (0 >= 4 as said in other answers).
    • Response from 0 >= 4 is then, evaluated in the next instruction, False causes than the code skip directly to the instruction 40 (Return False) without even test the last case.

    Of course, this is the bytecode explanation of how python works, the short answer is the 0 & n >= 6 & n thing, with this in mind, we can assume than every number different from 0, will return False to this evaluation, because a bitwise operation between b'0110' will always be greater than 0.

    TL;DR

    Bitwise operators are evaluated before Boolean operators.

    References

    https://docs.python.org/3.8/library/dis.html Dis module reference.