-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
bec738d
commit 6fa3be9
Showing
5 changed files
with
368 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
_hover over the explore ones and to make an issue if you want to work on that explore_ | ||
1. While we saw many types of gates today, but we actually could get all of the operations needed using only NAND gates. Work out how to use NAND gates to implement a half adder and describe it in {index}`nandhalf.md` | ||
2. In {index}`addertypes.md` compare ripple adders and lookahead adders. | ||
``` | ||
1. Give a synopsis of each adder type | ||
2. Compare them in terms of time (assume that each gate requires one unit of time) | ||
3. Compare them in terms of space/cost by counting the total number of gates required. | ||
``` | ||
3. Experiment with bitwise operators in python to derive 3 generic rules. Submit in `bitwise_expt.md` that has code in cells and the output (eg like the notes). An example (that you cannot get credit for) is any number xor with itself is 0, or `a^a =0`. | ||
- [ ] explore: Learn about the alternative to these operations for quantum computing and compare and think about how we would need to change computing operations for quantum compared to the traditional gates we have been using | ||
- [ ] explore: for another application of bitwsie operations, design and describe an activity |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
1. watch this short [video on an alternative adder](https://www.youtube.com/watch?v=GcDshWmhF4A) | ||
2. and this [video on half adder with legos](https://www.youtube.com/watch?v=5X_Ft4YR_wU) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
1. While we saw many types of gates today, but we actually could get all of the operations needed using only NAND gates. Work out how to use NAND gates to implement `and` and `or` in {index}`nandandor.md` | ||
1. Find what bitwise operation would complete each of these transformations (eg `1 << 3 = 4` and `4^4 = 0`) that is replace the ? with a bitwise operator. For each show work to explain how you found it in `bitwise.md`: | ||
``` | ||
4 ? 3 = 32 | ||
11 ? 7 = 3 | ||
8 ? 2 = 2 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,341 @@ | ||
--- | ||
file_format: mystnb | ||
kernelspec: | ||
name: python3 | ||
--- | ||
+++{"lesson_part": "main"} | ||
# How can we use logical operations? | ||
|
||
|
||
+++{"lesson_part": "main","type":"heading"} | ||
|
||
## Why do we need to think about bitwise operations? | ||
|
||
|
||
|
||
Understanding them is prereq to what we will see today and that will help you understand hardware overall. | ||
|
||
|
||
|
||
You of course will not *need* every single thing we teach you in every single class. | ||
|
||
|
||
|
||
* Seeing topics once at least is the only way you can make an informed decision to study a topic deeper or not. | ||
* Seeing a topic in more detail than you will use all the time actually helps you build intuition, or deep understanding, of the topic overall, and help you remember what you need to remember | ||
|
||
|
||
+++{"lesson_part": "main","type":"heading"} | ||
|
||
## Bitwise operators review | ||
|
||
|
||
|
||
- `&` : and | ||
- `|` : or | ||
- `^` : xor | ||
- `~` : not | ||
- `>>`: shift right | ||
- `<<`: shift left | ||
|
||
|
||
|
||
Let's review truth tables for and, or, and xor. | ||
|
||
+++{"lesson_part": "site","type":"table"} | ||
|
||
|
||
```{list-table} AND | ||
:header-rows: 1 | ||
:name: truth-and | ||
* - a | ||
- b | ||
- output | ||
* - 0 | ||
- 0 | ||
- 0 | ||
* - 0 | ||
- 1 | ||
- 0 | ||
* - 1 | ||
- 0 | ||
- 0 | ||
* - 1 | ||
- 1 | ||
- 1 | ||
``` | ||
|
||
|
||
|
||
|
||
```{list-table} OR | ||
:header-rows: 1 | ||
:name: truth-or | ||
* - a | ||
- b | ||
- output | ||
* - 0 | ||
- 0 | ||
- 0 | ||
* - 0 | ||
- 1 | ||
- 1 | ||
* - 1 | ||
- 0 | ||
- 1 | ||
* - 1 | ||
- 1 | ||
- 1 | ||
``` | ||
|
||
|
||
|
||
|
||
```{list-table} XOR | ||
:header-rows: 1 | ||
:name: truth-xor | ||
* - a | ||
- b | ||
- output | ||
* - 0 | ||
- 0 | ||
- 0 | ||
* - 0 | ||
- 1 | ||
- 1 | ||
* - 1 | ||
- 0 | ||
- 1 | ||
* - 1 | ||
- 1 | ||
- 0 | ||
``` | ||
|
||
|
||
|
||
In order to implement more complex calculations, using gates, we can use these tables as building blocks compared to the required output. | ||
|
||
|
||
|
||
There are more gate operations; you can see a simulation for [16 gates](https://lodev.org/logicemu/#id=gates16) | ||
|
||
+++{"lesson_part": "main","type":"heading"} | ||
|
||
|
||
## Adding with gates | ||
|
||
|
||
|
||
Let's review adding binary numbers. | ||
|
||
**remember, binary is a place-based system like the decimal placed based system you are likely familiar with** | ||
|
||
|
||
+++{"lesson_part": "main","type":"heading"} | ||
Since binary is place-based adding with binary follows the same basic algorithm | ||
|
||
- work right to left (smallest to largest place values) | ||
- add the two values in a given place | ||
- carry to the next place if >=2 | ||
|
||
|
||
+++{"lesson_part": "main"} | ||
$$ 101 + 100 = 1001 $$ | ||
|
||
|
||
|
||
We first add the ones place and get a 1, then the two's place and get a zero then the 4's place and get 0 with a carried one. | ||
|
||
+++{"lesson_part": "main"} | ||
|
||
$$ 010 + 011 = 101 $$ | ||
|
||
|
||
|
||
In this case in the ones place we add 0 + 1 to get one, the two ones add to 0 with carry then 1 + 0 + 0 gives another 1. | ||
|
||
|
||
+++{"lesson_part": "main"} | ||
|
||
let's make a truth table for adding two bits. | ||
|
||
|
||
+++{"lesson_part": "site"} | ||
|
||
```{list-table} Add | ||
:header-rows: 1 | ||
:name: truth-add | ||
* - a | ||
- b | ||
- a+b 2's | ||
- a+b 1's | ||
* - 0 | ||
- 0 | ||
- 0 | ||
- 0 | ||
* - 0 | ||
- 1 | ||
- 0 | ||
- 1 | ||
* - 1 | ||
- 0 | ||
- 0 | ||
- 1 | ||
* - 1 | ||
- 1 | ||
- 1 | ||
- 0 | ||
``` | ||
|
||
+++{"lesson_part": "main"} | ||
|
||
Now, what gate can we use to get the output 1's place bit and what gate can we use to get the output 2's place bit by comparing to the truth tables above. | ||
|
||
|
||
+++{"lesson_part": "main"} | ||
It turns out the one's place is an xor gate, and the two's place is an and gate. | ||
|
||
|
||
+++{"lesson_part": "main"} | ||
This makes up the [half adder, try one out at this simulator](https://lodev.org/logicemu/#id=half_adder). | ||
|
||
|
||
+++{"lesson_part": "main"} | ||
|
||
So this lets us as two bits, but what about adding a number with more bits? | ||
|
||
+++{"lesson_part": "main"} | ||
|
||
We can put multiple together, but there's one more wrinkle: the carry. | ||
|
||
|
||
+++{"lesson_part": "main"} | ||
|
||
That's what makes a [full adder](https://lodev.org/logicemu/#id=full_adder) different. It adds three single bits, or a carry and two bits and outputs the result as a sum bit and a carry bit. | ||
|
||
+++{"lesson_part": "main"} | ||
|
||
|
||
Then we can link many of those together to get an [8 bit ripple adder](https://lodev.org/logicemu/#id=ripple_carry_adder). | ||
|
||
|
||
|
||
Alternatively, we can "lookahead" with the carry bit, passing it forward multiple places all at once, as shown in this [4 bit carry lookahead adder](https://lodev.org/logicemu/#id=cla_adder). | ||
|
||
|
||
+++{"lesson_part": "main"} | ||
|
||
### Time vs space | ||
|
||
Then we can link many of those together to get an [8 bit ripple adder](https://lodev.org/logicemu/#id=ripple_carry_adder). | ||
|
||
|
||
|
||
Alternatively, we can "lookahead" with the carry bit, passing it forward multiple places all at once, as shown in this [4 bit carry lookahead adder](https://lodev.org/logicemu/#id=cla_adder). | ||
|
||
|
||
## Why do this? | ||
|
||
Workign through this example also reinforces not only the facts of how the binary works so that you can understand *how* a computer works. Working with these abstractions to break down higher level operations into components like this (addition is a more complex operation than `and` or `xor`) help you see how this can be done. | ||
|
||
Sometimes you have low level problems like resource constraints and bitwise operations can be useful. | ||
|
||
We may not do this all the time, but when we need it, we need it. | ||
|
||
for example, consider how to swap two values. | ||
|
||
+++{"lesson_part": "main"} | ||
|
||
Assume we have two variables `a` and `b` intitialized like: | ||
|
||
```{code-cell} python | ||
a =4 | ||
b =3 | ||
a,b | ||
``` | ||
|
||
+++{"lesson_part": "main"} | ||
|
||
The sort of intro to programming way to swap them uses a third variable: | ||
|
||
```{code-cell} python | ||
tmp = a | ||
a= b | ||
b = tmp | ||
a,b | ||
``` | ||
|
||
+++{"lesson_part": "main"} | ||
|
||
Let's reset them | ||
|
||
```{code-cell} python | ||
a =4 | ||
b =3 | ||
a,b | ||
``` | ||
|
||
+++{"lesson_part": "main"} | ||
|
||
::::{tip} | ||
Little tricks like this are sometimes the type of questions | ||
that get used in interviews, not that you should memorize all of the puzzle question answers, but that if you understand **all** of the concepts, you will be able to solve these sort of things in an interview | ||
:::: | ||
|
||
With bitwise operations we can swap them without a 3rd variable. | ||
|
||
```{code-cell} python | ||
a = a^b | ||
b = b^a | ||
a = a^b | ||
a,b | ||
``` | ||
|
||
+++{"lesson_part": "main"} | ||
|
||
|
||
If we implement this with only 3 bits we have a 1,2,4 places. | ||
|
||
![4 and 3 rpresented in binary in 2 registers labeled a and b](../img/xor_swap_0.svg) | ||
|
||
Then we xor each bit and store the result in the first register (our a variable) | ||
|
||
![4^3 and 3 represented in binary in 2 registers labeled a and b](../img/xor_swap_1.svg) | ||
|
||
and next we xor again and store in b | ||
|
||
![4^3 and 4 represented in binary in 2 registers labeled a and b](../img/xor_swap_2.svg) | ||
|
||
now the 4 has moved form A to B. If we xor one more time and store that in A, | ||
|
||
![3 and 4 represented in binary in 2 registers labeled a and b](../img/xor_swap_3.svg) | ||
|
||
+++{"lesson_part": "main"} | ||
|
||
|
||
```{code-cell} python | ||
b =874 | ||
a = 87435 | ||
a = a^b | ||
b = b^a | ||
a = a^b | ||
a,b | ||
``` | ||
|
||
|
||
|
||
|
||
+++{"lesson_part": "site","meta_type":"evidence"} | ||
## Experience Report Evidence | ||
|
||
|
||
|