Here is an alternate rendition of Nina's explanation, enhanced with additional visuals to facilitate comprehension of the concepts at the bit level.
Essential Knowledge
Before diving into the subject matter, it's crucial to understand that JavaScript can manipulate bits using the 0b
prefix. Familiarity with bitwise operators like "and" (&
) and "shift right" (>>
) is also advantageous:
> | 0b1
< | 1
> | 0b111
< | 7
> | (7).toString(2)
< | "111"
> | 1 & 1
< | 1
> | 1 & 0
< | 0
> | (0b101 & 0b110).toString(2)
< | "100"
> | (0b100 >> 1).toString(2)
< | "10"
> | (0b100 >> 2).toString(2)
< | "1"
> | (0b100 >> 3).toString(2)
< | "0"
In the equation L & R
, L
is commonly known as the "bit map," while R
is referred to as the "bit mask." The bit map comprises binary flags (0/1, off/on, false/true), while the bit mask acts as a selector:
flags | 0000111 | 0000111 | 0000111
& mask | & 0000001 | & 0000011 | & 0100100
= subset | = 0000001 | = 0000011 | = 0000100
In a binary number, the rightmost bit (bit 0) is termed the "least significant bit" (LSB), whereas the leftmost bit is the "most significant bit" (MSB):
> | 0b0000111 >> 0 & 1 // reads bit 0 (LSB)
< | 1
> | 0b0000111 >> 6 & 1 // reads bit 6 (MSB)
< | 0
Data Representation
Representation of days:
SFTWTMS <---- pay attention
0b0000001 = 1 = Sunday
0b0000010 = 2 = Monday
0b0000100 = 4 = Tuesday
0b0001000 = 8 = Wednesday
0b0010000 = 16 = Thursday
0b0100000 = 32 = Friday
0b1000000 = 64 = Saturday
Bit map indicating the selected days:
| SFTWTMS |
1 | 0b0000001 | Sunday
+ 2 | + 0b0000010 | + Monday
+ 4 | + 0b0000100 | + Tuesday
= 7 | = 0b0000111 | = selection
Visualization of the selected days' bit map, with explanatory notes:
Sat 0 drop (bit 6) <---- MSB
Fri 0 drop (bit 5)
Thu 0 drop (bit 4)
Wed 0 drop (bit 3)
Tue 1 take (bit 2)
Mon 1 take (bit 1)
Sun 1 take (bit 0) <---- LSB
Selection Process
This process entails reading the bit map from LSB to MSB:
for i in [0-6] do: take ith day if bitmap >> i & 1 equals 1
Step-by-step illustration:
SFTWTMS | S
0b0000111 >> 0 = 0b0000111 | 1
& 0b0000001 | & 1
= 0b0000001 | = 1 (take "Sun")
^ |
SFTWTM | M
0b0000111 >> 1 = 0b0000011 | 1
& 0b0000001 | & 1
= 0b0000001 | = 1 (take "Mon")
^
Example
Practical demonstration:
> | Sun = 0b0000001
< | 1
> | Mon = 0b0000010
< | 2
> | Tue = 0b0000100
< | 4
> | bitmap = Sun + Mon + Tue
< | 7
> | days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
< | ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
> | days.filter((_, i) => bitmap >> i & 1)
< | ["Sun", "Mon", "Tue"]
Note that the bit map can be interpreted as an array of booleans:
> | take = [true, true, true, false, false, false, false]
< | [true, true, true, false, false, false, false]
> | selection = []
< | []
> | for (i = 0; i < days.length; i++) {
| if (take[i]) selection.push(days[i]);
| }
| selection
< | ["Sun", "Mon", "Tue"]
Moreover, bitmap >> i & 1
("retrieve the ith bit") is equivalent to take[i]
("access the ith element"):
> | for (i = 0; i < 7; i++) {
| console.log(i, bitmap >> i & 1, take[i]);
| }
| 0 1 true
| 1 1 true
| 2 1 true
| 3 0 false
| ...