Bit Operations

This is an introduction to using bitwise operators and you'd learn how to do magical stuffs with them. So basically bit operations are used to manipulate bits (binary numbers) and here are the signs used:

Bitwise AND &

A bitwise AND is a binary operation that takes two bits and performs the logical AND operation on them. If the bits compared are 1, then bit in the resulting binary representation is 1 (1 & 1 = 1); otherwise, the result is 0 (1 & 0 = 0 and 0 & 0 = 0) source.

Here is a typical example:

A B A & B
0 0 0
1 0 0
0 1 0
1 1 1
5 & 4       |   1 0 1
5 = 101     | & 1 0 0
4 = 100       = 1 0 0  => 4

Bitwise OR |

A bitwise OR is a binary operation that takes two bits and performs the inclusive OR operation on them. If the bits compared are 0, the bit in the resulting binary representation is 1 (0 | 0 = 0); otherwise, the result is 0 (1 | 0 = 1 and 0 | 1 = 1) source.

Here is a typical example:

A B A | B
0 0 0
1 0 1
0 1 1
1 1 1
5 | 4       |   1 0 1
5 = 101     | | 1 0 0
4 = 100       = 1 0 1  => 5

Bitwise XOR ^

A bitwise XOR is a binary operation that takes two bits and performs the logical exclusive OR operation on them. If the bits compared are different, then bit in the resulting binary representation is 1 (1 ^ 0 = 1); otherwise, the result is 0 (1 ^ 1 = 0 and 0 ^ 0 = 0) source.

Here is a typical example:

A B A ^ B
0 0 0
1 0 1
0 1 0
1 1 0
5 ^ 4       |   1 0 1
5 = 101     | ^ 1 0 0
4 = 100       = 0 0 1  => 1

Bitwise Left Shift <<

In a left arithmetic shift, zeros are shifted in on the right; and the bits on the left are discarded source.

Here is a typical example:

5 << 2
5 = 101 |    [1] 0 1 0 << 1    (first shift)
        |     |      ^ added
        |     |------|
        | removed
        |
        |    [0] 1 0 0 << 2    (second shift)
        |     |      ^ added
        |     |------|
        | removed
       
        | 5 << 2 = 1 0 0 = 20

Tip: a << b = a * (2**b)

Bitwise Right Shift >>

In a right arithmetic shift, zeros are shifted in on the left; and the bits on the right are discarded source.

Here is a typical example:

5 >> 2
5 = 101 |       0 1 0 [1] >> 1    (first shift)
        | added ^      | 
        |       |------|
        |           removed
        |
        |       0 0 1 [0] >> 1    (second shift)
        | added ^      | 
        |       |------|
        |           removed
       
        | 5 >> 2 = 0 0 1 = 1

Tip: a >> b = a / (2**b)

Bitwise Not ~

The Not operator flips a bit i.e switching 1s to 0s and 0s to 1s.

Here is a typical example:

~ 103 | ~ 0000000001100111
      | = 1111111110011000 = -104

Why bitwise operations?

It's fast, especially when compaired to operations like /, * and %. Operations like / and * take too much time (O(n2)) for large numbers like (106) and also the % (modulus) operator takes (O(n3)) which is too much time for large numbers.

Example

Given you have a configuration for a simple website, where you can show choose what kind of theme you want (dark or light theme) and an option to open links in a new tab or same page.

There are 2 different selections and 4 different options given as:

  • Theme
    • Dark
    • Light
  • Open links
    • New tab
    • Same page

Most implementations, people would store these values on 2 different cookie slots in the browser and here we want to just store them in just one cookie since we have an understanding of bitwise operations.

Both options can be binary because we'd represent 0 for light-mode and 1 for dark-mode in the case of storing the theme.

cookie = 00 |   0    0 # 2 bits
            |   ^    ^
            |  Theme Open Links

Implementation in python


cookie = 0 # 0b00

def set_darkmode(value):
    """Sets the theme slot in the cookie
    
    Args:
        value (bool): sets the theme to dark if `True` 
                      else sets it to light
    """
    
    global cookie
    if value:
        cookie = cookie | (1 << 1) # sets theme to dark mode
    else:
        cookie = cookie & ~(1 << 1) # unsets dark mode

def set_openlinks(value):
    """Sets the openlink slot in the cookie
    
    Args:
        value (bool): sets the openlink to new-tab if `True` 
                      else sets it to same-page
    """
    
    global cookie
    if value:
        cookie = cookie | 1 # sets openlink to new-tab
    else:
        cookie = cookie & ~1 # unsets new-tab

def get_mode():
    # checks if the dark mode is set
    return "dark" if (cookie >> 1) & 1 else "light"

def get_openlinks():
    # checks if the new-tab bit is set
    return "new tab" if (cookie & 1) == 1 else "same page"

print(get_mode()) # light
print(get_openlinks()) # same page

set_openlinks(True)
set_darkmode(True)

print(get_mode()) # dark
print(get_openlinks()) # new tab

Also check out a much broader example in my previous article.

If you found this helpful, consider following me on Twitter @0xosas.