Bitwise operators in Python


Reading time: 30 minutes | Coding time: 5 minutes

&, |, ~, ^, <<, >> are called bitwise operators in Python (they are not language-specific and exist in almost all programming languages, but here we are going to use python to learn them)

Bitwise operators as the name suggests, operate on bits. They take integers as input, but the operations are performed on bits instead of the whole value.

  • &  does a 'bitwise and' written as x&y
  • |   does a 'bitwise or' written as x|y
  • ~  does a bitwise one's complement ~x
  • ^  does a 'bitwise exclusive or' written as x^y
  • <<  written as x << y, bits in x are shifted by y places to the left
  • >>  written as x>> y, bits in x are shifted by y places to the right

Let's see what each of the operators does in detail with examples.

Bitwise AND (&)

It takes two values as inputs and performs AND operation on them bit by bit.
AND is 1 if and only if both inputs are 1, else it's 0

i.e;

x  | y | x & y
0    0    0
0    1    0
1    0    0
1    1    1

example:

                x = 10      1010(in binary)
                y = 13      1101(in binary)
            
                1 0 1 0
             &  1 1 0 1
                1 0 0 0  = 8(in decimal) 

in python shell

>>> 10 & 13
8
>>> 5 & 8
0

Binary representation in Python

we can see binary values of a number using bin() function. similarly, int() can be used to convert back to decimal. These functions are quite useful since calculating binary of large values on paper is tedious.

>>> bin(41)
'0b101001'

some more examples

>>> 25 & 15                 
9
>>>bin(25), bin(15), bin(9)
('0b11001', '0b1111' ,'0b1001')      
>>> 51 & 21
17
>>>0b10100 & 0b11010        # 20 & 26 (in decimal)
16
>>>bin(16)
'0b10000'

now, in the event that lengths of input values are not equal, the one with smaller length is left padded with zeros to match the larger length

                  0b100010101 
                & 0b1011          
 
                  0b100010101   
    becomes     & 0b000001011

'&' operator doesn't work on strings and float values

>>> 'str1' & 'str2'
Type Error: unsupported operand type(s) for &:'str' and 'str'
>>> 2.5 & 3
Type Error: unsupported operand type(s) for &:'float' and 'int'

Lastly, '&' should not to be confused with 'and' in python.They are different from each other. we can see in the following example

>>> 6 and 13
13
>>> 6 & 13
4

'and' is a boolean operator which works on 'truthness' of values and has has nothing to do with bits. so do not confuse it with &(bitwise AND) operator.

Bitwise OR ( | )

It takes two values as inputs and performs OR operation on them bit by bit.
OR is 1 if one or both of its inputs are 1, else it's 0

x  | y | x|y
0    0    0
0    1    1
1    0    1
1    1    1

example:

                x = 10      1010(in binary)
                y = 13      1101(in binary)
            
                1 0 1 0
             |  1 1 0 1
                1 1 1 1  = 15(in decimal) 

in python shell:

>>> 10|13
15
>>> 0b10001 | 0b10101
21                             #10101 (in binary)

Bitwise XOR ( ^ )

It takes two values as inputs and performs exclusive-or(XOR) operation on them bit by bit.
XOR is 1 if only one of the inputs is 1, else it's 0

x  | y | x^y
0    0    0
0    1    1
1    0    1
1    1    0

example:

            x = 10      1010(in binary)
            y = 13      1101(in binary)
            
                1 0 1 0
             ^  1 1 0 1
                0 1 1 1  = 7(in decimal) 

in python shell:

>>> 10^13
7
>>> 0b11010 ^ 0b100
30
>>>bin(30)
'0b11110'

Bitwise 1's Complement ( ~)

This operator takes only one value as input and returns 1's complement of the number. so 1's become 0's and 0's become 1's. here, the output is the same as -x-1

 x | ~x
 0    1
 1    0

This operator is slightly different from other operators we have been learning. since python integers are signed, the results of this operator are not as intuitive as others.
example:

            x = 8      0000001000(in binary)
            
            0 0 0 0 0 0 1 0 0 0
      ~x    1 1 1 1 1 1 0 1 1 1  = -9

here in the above example the output is negative because as we discussed earlier,in python integers are signed. negative numbers are stored through a mechanism called 2's complement format.

in python shell:

>>>~8
-9
>>> ~11
-12

Bitwise left-shift ( << )

This operator takes two values as input and shifts the bits to left by a specified input.It shifts the bits to the left and adds zeros to the right end as we shift.
x << y: bits in x are shifted left by y places
examples

                   x = 13         1101(in binary)
                   y = 2
      
                  _ _ 1 1 0 1
   x << y         1 1 0 1 0 0    52(in decimal)

in the above example, every bit in 13 (binary 1101) is shifted by 2 places to the left.

>>> 13 <<2
52
>>> 0b10010 <<3
144
>>> bin(144)
10010000

a left shift in python is unusual as in it doesn't discard the bits shifted to the left, instead it expands width to accommodate the extra bits.

Bitwise right-shift ( >> )

This operator takes two values as input and shifts the bits to right by a specified input, discarding the bits to the right and adding zeros to the left end as we shift.
x >> y: bits in x are shifted right by y places
examples

                   x = 13            1101(in binary)
                   y = 2
      
                  1 1 0 1
   x >> y         0 0 1 1 0 1        3(in decimal)

as we can see in the above example,the bits shifted right are discarded.

>>> 13 >> 2
3
>>> 0b10010 >>3
2
>>> 0b1000 >>4
0

Question

What would be the output for the following

num is an integer
 num & 1023 
output is always 'num'
depends on value of 'num'
0
1
Since the binary of 1023 has all 1's, whatever we '&' it with gives the same number.