# 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](https://en.wikipedia.org/wiki/Bitwise_operation). 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](https://en.wikipedia.org/wiki/Bitwise_operation). 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](https://en.wikipedia.org/wiki/Bitwise_operation). 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](https://en.wikipedia.org/wiki/Bitwise_operation). 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](https://en.wikipedia.org/wiki/Bitwise_operation). 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($n^2$)) for large numbers like ($10^6$) and also the `%` (modulus) operator takes (O($n^3$)) 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 ```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](https://hackmd.io/@0xosas/S1uWnLChq). If you found this helpful, consider following me on Twitter [@0xosas](https://twitter.com/0xosas).