Skip to content

Commit 6b689cd

Browse files
Add bitwise concept (#722)
* Initial stub. * Adds stub for bitwise concept exericse (secrets) * Adds first draft of concept * Added notes on masking * Adds introduction.md (a copy of about.md) * Updates config and renames concept folder * Updates configs (lints OK now) * Updates allergies metadata to refer to bitwise-operations * Adds secrets exercise docs * Adds stub, example implementation, and tests * Removes the WIP status from the exercise * Fixes typo in the exercise instructions * Adds Secret handshake to bitwise exercises * Updates heading * Updates for consistency & formatting * Update for consistency with other exercises * Attempts to use templates * Updates to the templated * Simplified the examples. Added spacing. * Added general hint linking to package docs * Adds helpful links to the hints * Fixes typos in the hints * Adds 5th concept step to tie it all together * Formatting * Fixes doc bugs Fixes doc bugs * Add contribs * fix shift right examples * fix heading levels * tweak xor example * fox elm code blocks * fix merge conflict * fix headers, code blocks, and align introductions * add design.md file and instructions related to analyzer --------- Co-authored-by: Jeremie Gillet <jie.gillet@gmail.com>
1 parent 87013a2 commit 6b689cd

15 files changed

Lines changed: 675 additions & 4 deletions

File tree

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"authors": [
3+
"stewartmurrie"
4+
],
5+
"contributors": ["jiegillet"],
6+
"blurb": "Learn how to use integer bitwise operations in Elm"
7+
}
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
# About
2+
3+
## Bitwise operations
4+
5+
Bitwise operations allow us to manipulate individual digits within binary numbers.
6+
These operations are fundamental in computing, providing an efficient way to perform low-level tasks, such as controlling specific bits in memory, optimizing mathematical calculations, encryption, communications, and encoding/decoding data.
7+
8+
### Understanding 32-bit Integers in Elm
9+
10+
In Elm, integers are stored as 32-bit signed integers using [two's complement](https://en.wikipedia.org/wiki/Two%27s_complement) representation, meaning they use 32 binary digits (_bits_) to store each integer value.
11+
This bit limit affects the range of integers that Elm can represent directly:
12+
13+
Positive Range: 0 to 2<sup>31</sup> - 1 (or 0 to 2,147,483,647)
14+
Negative Range: -2<sup>31</sup> to -1 (or -2,147,483,648 to -1).
15+
16+
For example, the integer `5` is represented in binary as `00000000000000000000000000000101`, although usually we ignore the leading zeros and just say `101`.
17+
18+
### Bitwise
19+
20+
Elm provides several bitwise operators in its [Bitwise module](https://package.elm-lang.org/packages/elm/core/latest/Bitwise)
21+
22+
## Basic operations
23+
24+
Modifying individual bits of a number is called _masking_.
25+
A _mask_ is a number where specific bits have been set in a particular way to manipulate another number using bitwise operators such as `and`, `or`, and `xor`.
26+
27+
### and
28+
29+
`and` combines two numbers by keeping only the bits that are `1` in both.
30+
This is useful for checking to see if an individual bit is set.
31+
For example, to check if the 4th bit of a number is set to `1`, `and` it with a mask of `01000` (`8` in decimal) and see if the result is non-zero:
32+
33+
```elm
34+
Bitwise.and 13 8 --> 8
35+
-- 13 = 01101
36+
-- 8 = 01000
37+
-- and = 01000 = 8
38+
```
39+
40+
### or
41+
42+
`or` combines two numbers by setting each bit to `1` if it is `1` in either or both numbers.
43+
This is useful for setting a specific bit to `1`.
44+
For example, to set the 2nd bit in `10101`, `or` it with the mask `00010`:
45+
46+
```elm
47+
Bitwise.or 21 2 --> 23
48+
-- 21 = 10101
49+
-- 2 = 00010
50+
-- or = 10111 = 23
51+
```
52+
53+
### Exclusive-or (xor)
54+
55+
`xor` combines two numbers by setting each bit to `1` if it is `1` in one number but `0` in the other.
56+
This is useful for flipping a bit to its opposite value:
57+
58+
```elm
59+
Bitwise.xor 20 5 --> 17
60+
-- 20 = 10100
61+
-- 5 = 00101
62+
-- xor = 10001 = 17
63+
```
64+
65+
### Complement
66+
67+
`complement` inverts each bit of a number (`0` becomes `1`, `1` becomes `0`).
68+
69+
Note that this will result in positive numbers becoming negative, and negative numbers becoming positive.
70+
This is because negative numbers in binary are represented with `1` in the left-most position.
71+
72+
```elm
73+
Bitwise.complement 21 --> -22
74+
-- 21 = 00000000000000000000000000010101
75+
-- complement = 11111111111111111111111111101010 = -22
76+
```
77+
78+
### Bit shifting
79+
80+
The following operators move bits left or right by a specified number of positions, effectively multiplying or dividing by powers of 2.
81+
82+
`shiftLeftBy` moves bits to the left, filling in with `0` from the right-hand side.
83+
For example, to shift `21` left by 3 places:
84+
85+
```elm
86+
Bitwise.shiftLeftBy 3 21 --> 168
87+
-- 21 = 10101
88+
-- shiftLeftBy 3 = 10101000 = 168
89+
```
90+
91+
This is the same as saying `21 * 2^3 = 21 * 2 * 2 * 2 = 168`
92+
93+
`shiftRightBy`: Moves bits to the right:
94+
95+
```elm
96+
Bitwise.shiftRightBy 2 21 --> 5
97+
-- 21 = 10101
98+
-- shiftRightBy 2 = 00101 = 5
99+
```
100+
101+
Shifting to the right by 2 places is the same as integer division by 4.
102+
103+
Note that this function duplicates whatever value is in the leftmost bit.
104+
So, negative numbers will stay negative:
105+
106+
```elm
107+
Bitwise.shiftRightBy 3 -21 --> -3
108+
-- -21 = 111...101011
109+
-- shiftRightBy 3 = 111...11101 = -3
110+
```
111+
112+
If you want to shift right and fill in with zeros, use `shiftRightZfBy`:
113+
114+
```elm
115+
Bitwise.shiftRightZfBy 3 -21 --> 536870909
116+
-- -21 = 111...101011
117+
-- shiftRightZfBy 3 = 00111...11101 = 536870909
118+
```
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
# Introduction
2+
3+
Bitwise operations allow us to manipulate individual digits within binary numbers.
4+
5+
Elm provides several bitwise operators in its [Bitwise module](https://package.elm-lang.org/packages/elm/core/latest/Bitwise)
6+
7+
## Basic operations
8+
9+
Modifying individual bits of a number is called _masking_.
10+
A _mask_ is a number where specific bits have been set in a particular way to manipulate another number using bitwise operators such as `and`, `or`, and `xor`.
11+
12+
### and
13+
14+
`and` combines two numbers by keeping only the bits that are `1` in both.
15+
This is useful for checking to see if an individual bit is set.
16+
For example, to check if the 4th bit of a number is set to `1`, `and` it with a mask of `01000` (`8` in decimal) and see if the result is non-zero:
17+
18+
```elm
19+
Bitwise.and 13 8 --> 8
20+
-- 13 = 01101
21+
-- 8 = 01000
22+
-- and = 01000 = 8
23+
```
24+
25+
### or
26+
27+
`or` combines two numbers by setting each bit to `1` if it is `1` in either or both numbers.
28+
This is useful for setting a specific bit to `1`.
29+
For example, to set the 2nd bit in `10101`, `or` it with the mask `00010`:
30+
31+
```elm
32+
Bitwise.or 21 2 --> 23
33+
-- 21 = 10101
34+
-- 2 = 00010
35+
-- or = 10111 = 23
36+
```
37+
38+
### Exclusive-or (xor)
39+
40+
`xor` combines two numbers by setting each bit to `1` if it is `1` in one number but `0` in the other.
41+
This is useful for flipping a bit to its opposite value:
42+
43+
```elm
44+
Bitwise.xor 20 5 --> 17
45+
-- 20 = 10100
46+
-- 5 = 00101
47+
-- xor = 10001 = 17
48+
```
49+
50+
### Complement
51+
52+
`complement` inverts each bit of a number (`0` becomes `1`, `1` becomes `0`).
53+
54+
Note that this will result in positive numbers becoming negative, and negative numbers becoming positive.
55+
This is because negative numbers in binary are represented with `1` in the left-most position.
56+
57+
```elm
58+
Bitwise.complement 21 --> -22
59+
-- 21 = 00000000000000000000000000010101
60+
-- complement = 11111111111111111111111111101010 = -22
61+
```
62+
63+
### Bit shifting
64+
65+
The following operators move bits left or right by a specified number of positions, effectively multiplying or dividing by powers of 2.
66+
67+
`shiftLeftBy` moves bits to the left, filling in with `0` from the right-hand side.
68+
For example, to shift `21` left by 3 places:
69+
70+
```elm
71+
Bitwise.shiftLeftBy 3 21 --> 168
72+
-- 21 = 10101
73+
-- shiftLeftBy 3 = 10101000 = 168
74+
```
75+
76+
This is the same as saying `21 * 2^3 = 21 * 2 * 2 * 2 = 168`
77+
78+
`shiftRightBy`: Moves bits to the right:
79+
80+
```elm
81+
Bitwise.shiftRightBy 2 21 --> 5
82+
-- 21 = 10101
83+
-- shiftRightBy 2 = 00101 = 5
84+
```
85+
86+
Shifting to the right by 2 places is the same as integer division by 4.
87+
88+
Note that this function duplicates whatever value is in the leftmost bit.
89+
So, negative numbers will stay negative:
90+
91+
```elm
92+
Bitwise.shiftRightBy 3 -21 --> -3
93+
-- -21 = 111...101011
94+
-- shiftRightBy 3 = 111...11101 = -3
95+
```
96+
97+
If you want to shift right and fill in with zeros, use `shiftRightZfBy`:
98+
99+
```elm
100+
Bitwise.shiftRightZfBy 3 -21 --> 536870909
101+
-- -21 = 111...101011
102+
-- shiftRightZfBy 3 = 00111...11101 = 536870909
103+
```
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[
2+
{
3+
"url": "https://package.elm-lang.org/packages/elm/core/latest/Bitwise",
4+
"description": "Bitwise module"
5+
},
6+
{
7+
"url": "https://guide.elm-lang.org/appendix/types_as_bits",
8+
"description": "Documentation on how Elm represents types as bits"
9+
}
10+
]

config.json

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,19 @@
356356
],
357357
"status": "beta"
358358
},
359+
{
360+
"slug": "secrets",
361+
"name": "Secrets",
362+
"uuid": "89a899b1-8cb2-4099-98c9-468723728a28",
363+
"concepts": [
364+
"bitwise-operations"
365+
],
366+
"prerequisites": [
367+
"basics-1",
368+
"basics-2"
369+
],
370+
"status": "beta"
371+
},
359372
{
360373
"slug": "githup-api",
361374
"name": "GitHup API",
@@ -539,11 +552,14 @@
539552
"slug": "allergies",
540553
"name": "Allergies",
541554
"uuid": "29b5a28a-417a-4cee-ba6f-9dd942ceffaa",
542-
"practices": [],
543-
"prerequisites": [],
555+
"practices": [
556+
"bitwise-operations"
557+
],
558+
"prerequisites": [
559+
"bitwise-operations"
560+
],
544561
"difficulty": 4,
545562
"topics": [
546-
"bitwise_operations",
547563
"enumerations",
548564
"filtering"
549565
]
@@ -1291,8 +1307,11 @@
12911307
"slug": "secret-handshake",
12921308
"name": "Secret Handshake",
12931309
"uuid": "6c7a96ec-0bfb-4284-bd9f-2aa6989c3bb5",
1294-
"practices": [],
1310+
"practices": [
1311+
"bitwise-operations"
1312+
],
12951313
"prerequisites": [
1314+
"bitwise-operations",
12961315
"custom-types",
12971316
"pattern-matching",
12981317
"maybe",
@@ -1546,6 +1565,11 @@
15461565
"slug": "random",
15471566
"name": "Random"
15481567
},
1568+
{
1569+
"uuid": "8737961b-c96f-4313-8737-6b88034c66d8",
1570+
"slug": "bitwise-operations",
1571+
"name": "Bitwise Operations"
1572+
},
15491573
{
15501574
"uuid": "d3864c81-b7e4-4b42-87d1-aac069ecb839",
15511575
"slug": "web-applications-sandbox",
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Hints
2+
3+
- The documentation for the `Bitwise` package can be found [here][bitwise-docs].
4+
5+
## 1. Shift back the bits
6+
7+
- There are two functions for shifting bits to the right, but [only one][bitwise-shiftRightZfBy] will always insert a 0.
8+
9+
## 2. Set some bits
10+
11+
- [One of the bitwise functions][bitwise-or] will always set a bit to 1 where the bits in both values are 1.
12+
13+
## 3. Flip specific bits
14+
15+
- There is [a bitwise function][bitwise-xor] that will flip a bit where the mask is 1.
16+
17+
## 4. Clear specific bits
18+
19+
- [One of the bitwise functions][bitwise-and] clears bits where the bit in the mask is 0.
20+
- But, you may need to combine it with [another function][bitwise-complement] to clear bits where the mask is 1.
21+
22+
## 5. Decrypt a message
23+
24+
- Apply the other functions you wrote to the input in the following order, taking the output of one and using it as the input to the next one:
25+
26+
1. `setBits`
27+
2. `flipBits`
28+
3. `shiftBack`
29+
4. `clearBits`
30+
31+
For step 4, you'll need to convert the binary number with the 1st and 5th bits set (10001) to decimal.
32+
33+
[bitwise-docs]: https://package.elm-lang.org/packages/elm/core/latest/Bitwise
34+
[bitwise-shiftRightZfBy]: https://package.elm-lang.org/packages/elm/core/latest/Bitwise#shiftRightZfBy
35+
[bitwise-or]: https://package.elm-lang.org/packages/elm/core/latest/Bitwise#or
36+
[bitwise-xor]: https://package.elm-lang.org/packages/elm/core/latest/Bitwise#xor
37+
[bitwise-complement]: https://package.elm-lang.org/packages/elm/core/latest/Bitwise#complement
38+
[bitwise-and]: https://package.elm-lang.org/packages/elm/core/latest/Bitwise#and

0 commit comments

Comments
 (0)