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 all 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": ["jiegillet"],
"blurb": "Learn how to use integer bitwise operations in Elm"
}
117 changes: 117 additions & 0 deletions concepts/bitwise-operations/about.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# About

## Bitwise operations

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

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.
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

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


### 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.
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.
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

#### 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
```

Shifting 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
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
-- shiftRightZfBy 3 = 00111...11101 = 1073741818
```
104 changes: 104 additions & 0 deletions concepts/bitwise-operations/introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# Introduction

Bitwise operations allow us to manipulate individual digits within binary numbers.

## 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.
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


### or

`or` combines two numbers by setting each bit to `1` if it is `1` in either or both numbers.
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.
This is useful for flipping a bit to its opposite value:

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

### 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
```

Shifting 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
-- shiftRightZfBy 3 = 00111...11101 = 1073741818
```
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"
}
]
31 changes: 27 additions & 4 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,18 @@
"booleans"
],
"status": "beta"
},
{
"slug": "secrets",
"name": "Secrets",
"uuid": "89a899b1-8cb2-4099-98c9-468723728a28",
"concepts": [
"bitwise-operations"
],
"prerequisites": [
"basics-1",
"basics-2"
]
}
],
"practice": [
Expand Down Expand Up @@ -503,11 +515,14 @@
"slug": "allergies",
"name": "Allergies",
"uuid": "29b5a28a-417a-4cee-ba6f-9dd942ceffaa",
"practices": [],
"prerequisites": [],
"practices": [
"bitwise-operations"
],
"prerequisites": [
"bitwise-operations"
],
"difficulty": 4,
"topics": [
"bitwise_operations",
"enumerations",
"filtering"
]
Expand Down Expand Up @@ -1255,8 +1270,11 @@
"slug": "secret-handshake",
"name": "Secret Handshake",
"uuid": "6c7a96ec-0bfb-4284-bd9f-2aa6989c3bb5",
"practices": [],
"practices": [
"bitwise-operations"
],
"prerequisites": [
"bitwise-operations",
"custom-types",
"pattern-matching",
"maybe",
Expand Down Expand Up @@ -1505,6 +1523,11 @@
"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
38 changes: 38 additions & 0 deletions exercises/concept/secrets/.docs/hints.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Hints

- The documentation for the `Bitwise` package can be found [here][bitwise-docs].

## 1. Shift back the bits

- There are two functions for shifting bits to the right, but [only one][bitwise-shiftRightZfBy] will always insert a 0.

## 2. Set some bits

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

## 3. Flip specific bits

- There is [a bitwise function][bitwise-xor] that will flip a bit where the mask is 1.

## 4. Clear specific bits

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

## 5. Decrypt a message

- 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:

1. `setBits`
2. `flipBits`
3. `shiftBack`
4. `clearBits`

For step 4, you'll need to convert the binary number with the 1st and 5th bits set (10001) to decimal.

[bitwise-docs]: https://package.elm-lang.org/packages/elm/core/latest/Bitwise
[bitwise-shiftRightZfBy]: https://package.elm-lang.org/packages/elm/core/latest/Bitwise#shiftRightZfBy
[bitwise-or]: https://package.elm-lang.org/packages/elm/core/latest/Bitwise#or
[bitwise-xor]: https://package.elm-lang.org/packages/elm/core/latest/Bitwise#xor
[bitwise-complement]: https://package.elm-lang.org/packages/elm/core/latest/Bitwise#complement
[bitwise-and]: https://package.elm-lang.org/packages/elm/core/latest/Bitwise#and
Loading