Skip to content

Bitwise Operators#

Before you proceed, you should have a better understanding about Binary Numbers. See this blog post to learn more.

Bitwise operators is best suited when dealing with binary values and writing algorithms for encoding/encryption.

Why use them?#

Disclaimer

This blog post is NOT associated with the YouTube video provided below, or vice-versa but just used as a reference or a source.

https://www.youtube.com/embed/igIjGxF2J-w?si=TUusxlLH62WV4j7E
The smallest amount of space that a variable can take up is one byte.
A boolean variable only have true or false and should only really take up one bit.
But in fact, it takes up 1 byte and the rest of 7 bits are wasted.

0000 0001 = true

This is not great if you've got a limited amount of memory.

Save Space#

To save space, you can store multiple boolean flags in just 1 byte (max 8 flags).

Example: Permissions#

Real example can be seen on Unix filesystems where you may have seen file permissions with things like:

  • 644
  • 777
  • 755
bash terminal
stat README.md

Output

File: README.md
...
Access: (0644/-rw-r--r--)

These 3 numbers makes up the different groups for the permission.

owner everyone group
6 4 4

Each numbers tells about the permission that a particular group has.

To really understand the numbers, we have to convert them into binary first.

Number Binary Description
7 111 read, write, execute
6 110 read, write
4 100 read

Permission Number#

Permission Number Binary
Read (r) 4 100
Write (w) 2 010
Execute (x) 1 001

Operators#

The following table shows Bitwise Operators

Operator Name
& AND
| OR
^ XOR (Exclusive OR)
~ NOT
<< left shift
>> right shift

AND Operator (&)#

Compares 2 values, If both bits are equal to 1 then return 1

7 & 6

7 = 0b111
6 = 0b110

7 6 Result
1 1 1
1 1 1
1 0 0

7 & 6 = 6

console.log(7 & 6); // 6
console.log(6 & 4); // 4

(&) Application#

Identify access

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/* JavaScript

Access:
    # | r | w | x |
    ---------------
    7 | 1 | 1 | 1 |
    6 | 1 | 1 | 0 |
    4 | 1 | 0 | 0 |
      -------------
      | 4 | 2 | 1 | (Permissions)

Permissions:
    4 | 1 0 0   Read
    2 |   1 0   Write
    1 |     1   Execute
*/
const READ = 4;    // 0b100
const WRITE = 2;   // 0b010
const EXECUTE = 1; // 0b001

const USER_ACCESS = 6;

if ((USER_ACCESS & READ) === READ) {
  console.log('can read');
}

/* 

If both bits **are equal** to `1` then return `1`

|  6  |  4  | Result |
| :-: | :-: | :----: |
|  1  |  1  |   1    |
|  1  |  0  |   0    |
|  0  |  0  |   0    |

6 & 4 = 4

*/
console.log(USER_ACCESS & READ); // 4

OR Operator (|)#

Compares 2 values, If both bits have at least 1 then return 1

7 & 6

7 = 0b111
6 = 0b110

7 6 Result
1 1 1
1 1 1
1 0 1

7 | 6 = 7
4 | 2 = 6

(|) Application#

Add access

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
/* JavaScript

Access:
    # | r | w | x |
    ---------------
    7 | 1 | 1 | 1 |
    6 | 1 | 1 | 0 |
    4 | 1 | 0 | 0 |
      -------------
      | 4 | 2 | 1 | (Permissions)

Permissions:
    4 | 1 0 0   Read
    2 |   1 0   Write
    1 |     1   Execute
*/
const READ = 4;    // 0b100
const WRITE = 2;   // 0b010
const EXECUTE = 1; // 0b001

let USER_ACCESS = READ | WRITE


/*

If both bits have **at least** `1` then return `1`

|  4  |  2  | Result |
| :-: | :-: | :----: |
|  1  |  0  |   1    |
|  0  |  1  |   1    |
|  0  |  0  |   0    |

4 | 2 = 6

*/
console.log(USER_ACCESS) // 6

/* Grant additional access

|  6  |  1  | Result |
| :-: | :-: | :----: |
|  1  |  0  |   1    |
|  1  |  0  |   1    |
|  0  |  1  |   1    |

6 | 1 = 7

*/

USER_ACCESS |= EXECUTE // grants additional access

console.log(USER_ACCESS) // 7

XOR Operator (^)#

Exclusive OR operator

Compares 2 values, If both are opposite, then return 1

7 = 0b111
6 = 0b110

7 6 Result
1 1 0
1 1 0
1 0 1

7 ^ 6 = 1 6 ^ 2 = 4

(^) Application#

Remove access

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
/* JavaScript

Access:
    # | r | w | x |
    ---------------
    7 | 1 | 1 | 1 |
    6 | 1 | 1 | 0 |
    4 | 1 | 0 | 0 |
      -------------
      | 4 | 2 | 1 | (Permissions)

Permissions:
    4 | 1 0 0   Read
    2 |   1 0   Write
    1 |     1   Execute
*/
const READ = 4; // 0b100
const WRITE = 2; // 0b010
const EXECUTE = 1; // 0b001

let USER_ACCESS = READ | WRITE;

USER_ACCESS ^= WRITE;

/*

If both are **opposite**, then return `1`

|  6  |  2  | Result |
| :-: | :-: | :----: |
|  1  |  0  |   1    |
|  1  |  1  |   0    |
|  0  |  0  |   0    |

6 ^ 2 = 4

*/

console.log(USER_ACCESS); // 4

NOT Operator (~)#

Unlike the other operators, NOT Operator does not compare and only works on 1 value.

~5 (0b101) = 0b010
~5 = -6

Instead of 2 (0b010), you'll get a negative number!
That is -6

Since 1 byte is 8-bit, it's actually flipping all values.

0b00000101 (5) to 0b11111010 (-6)

If you remember the table (see this blog post in new tab), it would give us this equation:

27 26 25 24 23 22 21 20
1 1 1 1 1 0 1 0

-128 + 64 + 32 + 16 + 8 + 0 + 2 + 0 = -6

Left & Right Shift (<<, >>)#

It shifts the bits either left or right.

Like the NOT Operator (~), Left or Right shift also used on 1 value, and the second number denotes how many bits you want to shift the number by.

5 << 2

Shift bits to left by 2
  Given:  0000 0101
  Output: 0001 0100

Shift bits to right by 2
  Given:  0001 0100
  Output: 0000 0101

5 << 2 = 20
20 >> 2 = 5

Conclusion#

Learning about how binary is stored in computers can help you save memory space such as the given example on how we can store multiple boolean flags in 1-byte and use &, | and ^ operators to read, add, remove access permissions, respectively.

Working with binary data is best suited for writing algorithms on encryptions and decryptions or simply saving memory space when handling multiple boolean flags efficiently.

Comments