Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add bitwise concept #722

Open
wants to merge 26 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
90ed84e
Initial stub.
stewartmurrie Nov 2, 2024
906a767
Adds stub for bitwise concept exericse (secrets)
stewartmurrie Nov 2, 2024
c925970
Adds first draft of concept
stewartmurrie Nov 2, 2024
52770b9
Added notes on masking
stewartmurrie Nov 3, 2024
82e0424
Adds introduction.md (a copy of about.md)
stewartmurrie Nov 3, 2024
77679ee
Updates config and renames concept folder
stewartmurrie Nov 3, 2024
cbbe48f
Updates configs (lints OK now)
stewartmurrie Nov 3, 2024
2f18e88
Updates allergies metadata to refer to bitwise-operations
stewartmurrie Nov 3, 2024
2d5dea3
Adds secrets exercise docs
stewartmurrie Nov 3, 2024
9a17e1c
Adds stub, example implementation, and tests
stewartmurrie Nov 3, 2024
6e4d3f3
Removes the WIP status from the exercise
stewartmurrie Nov 5, 2024
f8fca1a
Fixes typo in the exercise instructions
stewartmurrie Nov 5, 2024
b073b12
Adds Secret handshake to bitwise exercises
stewartmurrie Nov 7, 2024
54545de
Updates heading
stewartmurrie Nov 7, 2024
b0cf475
Updates for consistency & formatting
stewartmurrie Nov 7, 2024
7d00134
Update for consistency with other exercises
stewartmurrie Nov 7, 2024
aa79d27
Attempts to use templates
stewartmurrie Nov 17, 2024
ce39d30
Updates to the templated
stewartmurrie Nov 17, 2024
fc09e07
Simplified the examples. Added spacing.
stewartmurrie Nov 17, 2024
e76389a
Added general hint linking to package docs
stewartmurrie Nov 17, 2024
6ceb47f
Adds helpful links to the hints
stewartmurrie Nov 17, 2024
40ad002
Fixes typos in the hints
stewartmurrie Nov 17, 2024
6a60cab
Adds 5th concept step to tie it all together
stewartmurrie Nov 17, 2024
662f383
Formatting
stewartmurrie Nov 17, 2024
d7cfa4b
Fixes doc bugs
stewartmurrie Nov 24, 2024
0ca8335
Add contribs
stewartmurrie Nov 24, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions concepts/bitwise-operations/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"authors": [
"stewartmurrie"
],
"contributors": [ ],
"blurb": "Learn how to use integer bitwise operations in Elm"
}
142 changes: 142 additions & 0 deletions concepts/bitwise-operations/about.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
# Bitwise Operations
stewartmurrie marked this conversation as resolved.
Show resolved Hide resolved

Bitwise operations allow us to manipulate individual digits within binary numbers. 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.
stewartmurrie marked this conversation as resolved.
Show resolved Hide resolved

## Understanding 32-bit Integers in Elm

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. This bit limit affects the range of integers that Elm can represent directly:

Positive Range: 0 to 2<sup>^31</sup> - 1 (or 0 to 2,147,483,647)
stewartmurrie marked this conversation as resolved.
Show resolved Hide resolved
stewartmurrie marked this conversation as resolved.
Show resolved Hide resolved
Negative Range: -2<sup>^31</sup> to -1 (or -2,147,483,648 to -1)
stewartmurrie marked this conversation as resolved.
Show resolved Hide resolved

For example, the integer `5` is represented in binary as `00000000000000000000000000000101`, although usually we ignore the leading zeros and just say `101`.

## Bitwise operations

Elm provides several bitwise operators in its [Bitwise module](https://package.elm-lang.org/packages/elm/core/latest/Bitwise)

## Basic operations

Modifying individual bits of a number is called _masking_. 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`.

### and

`and` combines two numbers by keeping only the bits that are `1` in both. For example:

```elm
Bitwise.and 21 13 --> 5
-- 21 = 10101
-- 13 = 01101
-- and = 00101 = 5
```

This is useful for checking to see if an individual bit is set. 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:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These documents are mostly meant to explain Elm's syntax, not so much explain the concepts in details. I really like your explanations though, so I don't want to cut them, but I would cut the extra examples, one is enough.
Same for the other sections.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I tried consolidating the examples. Let me know if you like them.


```elm
Bitwise.and 13 8 --> 8
-- 13 = 01101
-- 8 = 01000
-- and = 01000 = 8

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is an extra blank line here I think

Bitwise.and 21 8 -> 0
-- 21 = 10101
-- 8 = 01000
-- and = 00000 = 0
```

### or
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be a level 4 heading


`or` combines two numbers by setting each bit to `1` if it is `1` in either or both numbers.

```elm
Bitwise.or 21 13 --> 29
-- 21 = 10101
-- 13 = 01101
-- or = 11101 = 29
```

This is useful for setting a specific bit to `1`. For example, to set the 2nd bit in `10101`, `or` it with the mask `00010`:

```elm
Bitwise.or 21 2 --> 23
-- 21 = 10101
-- 2 = 00010
-- or = 10111 = 23
```

### Exclusive-or (xor)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be a level 4 heading


`xor` combines two numbers by setting each bit to `1` if it is `1` in one number but `0` in the other.

```elm
Bitwise.xor 21 13 --> 24
-- 21 = 10101
-- 13 = 01101
-- xor = 11000 = 24
```

This is useful for flipping a bit to its opposite value:

```elm
Bitwise.xor 21 4 --> 17
-- 21 = 10101
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be better to use 20 and 5 here, so that you can see that it works both ways round. ( 0 - 1 and 1 - 0 )

-- 4 = 00100
-- xor = 10001 = 17

Bitwise.xor 17 4 --> 21
-- 17 = 10001
-- 4 = 00100
-- xor = 10101 = 21
```

### Complement

`complement` inverts each bit of a number (`0` becomes `1`, `1` becomes `0`).

Note that this will result in positive numbers becoming negative, and negative numbers becoming positive. This is because negative numbers in binary are represented with `1` in the left-most position.

```elm
Bitwise.complement 21 --> -22
-- 21 = 00000000000000000000000000010101
-- complement = 11111111111111111111111111101010 = -22
```

## Bit shifting

The following operators move bits left or right by a specified number of positions, effectively multiplying or dividing by powers of 2.

`shiftLeftBy` moves bits to the left, filling in with `0` from the right-hand side. For example, to shift `21` left by 3 places:

```elm
Bitwise.shiftLeftBy 3 21 --> 168
-- 21 = 10101
-- shiftLeftBy 3 = 10101000 = 168
```

This is the same as saying `21 * 2^3 = 21 * 2 * 2 * 2 = 168`

`shiftRightBy`: Moves bits to the right:

```elm
Bitwise.shiftRightBy 2 21 --> 5
-- 21 = 10101
-- shiftRightBy 2 = 00101 = 5
```

Shifiting to the right by 2 places is the same as integer division by 4.
stewartmurrie marked this conversation as resolved.
Show resolved Hide resolved

Note that this function duplicates whatever value is in the leftmost bit. So negative numbers will stay negative:

```elm
Bitwise.shiftRightBy 3 -21 --> -6
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not what I'm getting from elm repl

> import Bitwise
> import BitwisBitwise.shiftRightBy 3 -21
-3 : Int

also -21 should be 111...101011 according to my calculator app.

-- -21 = 111...10101
-- shiftRightBy 3 = 111...11101 = -6
```

If you want to shift right and fill in with zeros, use `shiftRightZfBy`:

```elm
Bitwise.shiftRightZfBy 3 -21 --> 1073741818
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is also not what I'm getting, I get

> Bitwise.shiftRightZfBy 3 -21
536870909 : Int

-- -21 = 111...10101
-- shiftRightBy 3 = 00111...11101 = 1073741818
stewartmurrie marked this conversation as resolved.
Show resolved Hide resolved
```
142 changes: 142 additions & 0 deletions concepts/bitwise-operations/introduction.md
stewartmurrie marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
# About Bitwise Operations
stewartmurrie marked this conversation as resolved.
Show resolved Hide resolved

Bitwise operations allow us to manipulate individual digits within binary numbers. 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.

## Understanding 32-bit Integers in Elm
stewartmurrie marked this conversation as resolved.
Show resolved Hide resolved

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. This bit limit affects the range of integers that Elm can represent directly:

Positive Range: 0 to 2<sup>^31</sup> - 1 (or 0 to 2,147,483,647)
Negative Range: -2<sup>^31</sup> to -1 (or -2,147,483,648 to -1)

For example, the integer `5` is represented in binary as `00000000000000000000000000000101`, although usually we ignore the leading zeros and just say `101`.

## Bitwise operations

Elm provides several bitwise operators in its [Bitwise module](https://package.elm-lang.org/packages/elm/core/latest/Bitwise)

## Basic operations

Modifying individual bits of a number is called _masking_. 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`.

### and

`and` combines two numbers by keeping only the bits that are `1` in both. For example:

```elm
Bitwise.and 21 13 --> 5
-- 21 = 10101
-- 13 = 01101
-- and = 00101 = 5
```

This is useful for checking to see if an individual bit is set. 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:

```elm
Bitwise.and 13 8 --> 8
-- 13 = 01101
-- 8 = 01000
-- and = 01000 = 8

Bitwise.and 21 8 -> 0
-- 21 = 10101
-- 8 = 01000
-- and = 00000 = 0
```

### or

`or` combines two numbers by setting each bit to `1` if it is `1` in either or both numbers.

```elm
Bitwise.or 21 13 --> 29
-- 21 = 10101
-- 13 = 01101
-- or = 11101 = 29
```

This is useful for setting a specific bit to `1`. For example, to set the 2nd bit in `10101`, `or` it with the mask `00010`:

```elm
Bitwise.or 21 2 --> 23
-- 21 = 10101
-- 2 = 00010
-- or = 10111 = 23
```

### Exclusive-or (xor)

`xor` combines two numbers by setting each bit to `1` if it is `1` in one number but `0` in the other.

```elm
Bitwise.xor 21 13 --> 24
-- 21 = 10101
-- 13 = 01101
-- xor = 11000 = 24
```

This is useful for flipping a bit to its opposite value:

```elm
Bitwise.xor 21 4 --> 17
-- 21 = 10101
-- 4 = 00100
-- xor = 10001 = 17

Bitwise.xor 17 4 --> 21
-- 17 = 10001
-- 4 = 00100
-- xor = 10101 = 21
```

### Complement

`complement` inverts each bit of a number (`0` becomes `1`, `1` becomes `0`).

Note that this will result in positive numbers becoming negative, and negative numbers becoming positive. This is because negative numbers in binary are represented with `1` in the left-most position.

```elm
Bitwise.complement 21 --> -22
-- 21 = 00000000000000000000000000010101
-- complement = 11111111111111111111111111101010 = -22
```

## Bit shifting

The following operators move bits left or right by a specified number of positions, effectively multiplying or dividing by powers of 2.

`shiftLeftBy` moves bits to the left, filling in with `0` from the right-hand side. For example, to shift `21` left by 3 places:

```elm
Bitwise.shiftLeftBy 3 21 --> 168
-- 21 = 10101
-- shiftLeftBy 3 = 10101000 = 168
```

This is the same as saying `21 * 2^3 = 21 * 2 * 2 * 2 = 168`

`shiftRightBy`: Moves bits to the right:

```elm
Bitwise.shiftRightBy 2 21 --> 5
-- 21 = 10101
-- shiftRightBy 2 = 00101 = 5
```

Shifiting to the right by 2 places is the same as integer division by 4.

Note that this function duplicates whatever value is in the leftmost bit. So negative numbers will stay negative:

```elm
Bitwise.shiftRightBy 3 -21 --> -6
-- -21 = 111...10101
-- shiftRightBy 3 = 111...11101 = -6
```

If you want to shift right and fill in with zeros, use `shiftRightZfBy`:

```elm
Bitwise.shiftRightZfBy 3 -21 --> 1073741818
-- -21 = 111...10101
-- shiftRightBy 3 = 00111...11101 = 1073741818
stewartmurrie marked this conversation as resolved.
Show resolved Hide resolved
```
10 changes: 10 additions & 0 deletions concepts/bitwise-operations/links.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[
{
"url": "https://package.elm-lang.org/packages/elm/core/latest/Bitwise",
"description": "Bitwise module"
},
{
"url": "https://guide.elm-lang.org/appendix/types_as_bits",
"description": "Documentation on how Elm represents types as bits"
}
]
stewartmurrie marked this conversation as resolved.
Show resolved Hide resolved
18 changes: 15 additions & 3 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,13 @@
"booleans"
],
"status": "beta"
},
{
"slug": "secrets",
"name": "secrets",
stewartmurrie marked this conversation as resolved.
Show resolved Hide resolved
"uuid": "89a899b1-8cb2-4099-98c9-468723728a28",
"concepts": ["bitwise-operations"],
"prerequisites": ["basics-1", "basics-2"]
stewartmurrie marked this conversation as resolved.
Show resolved Hide resolved
}
],
"practice": [
Expand Down Expand Up @@ -503,11 +510,10 @@
"slug": "allergies",
"name": "Allergies",
"uuid": "29b5a28a-417a-4cee-ba6f-9dd942ceffaa",
"practices": [],
"prerequisites": [],
"practices": ["bitwise-operations"],
"prerequisites": ["bitwise-operations"],
stewartmurrie marked this conversation as resolved.
Show resolved Hide resolved
"difficulty": 4,
"topics": [
"bitwise_operations",
"enumerations",
"filtering"
]
Expand Down Expand Up @@ -1505,7 +1511,13 @@
"uuid": "357ffb6e-5a73-49b6-8b69-98ecd3c74c33",
"slug": "random",
"name": "Random"
},
{
"uuid": "8737961b-c96f-4313-8737-6b88034c66d8",
"slug": "bitwise-operations",
"name": "Bitwise Operations"
}

],
"key_features": [
{
Expand Down
18 changes: 18 additions & 0 deletions exercises/concept/secrets/.docs/hints.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Hints
stewartmurrie marked this conversation as resolved.
Show resolved Hide resolved

## 1. Shift back the bits

- There are two functions for shifting bits to the right, but only one will always insert a 0.
stewartmurrie marked this conversation as resolved.
Show resolved Hide resolved

## 2. Set some bits

- One of the bitwise functions will always set a bit to 1 where the bits in both values are 1.

## 3. Flip specific bits

- There is an bitwise function that will flip a bit where the mask is 1.

## 4. Clear specific bits

- One of the bitwise functions clears bits where the bit in the mask is 0.
- But you may need to combine it with another function to clear bits where the mask is 1.
Loading
Loading