diff --git a/pretext/AdditionalTopics/BigO.ptx b/pretext/AdditionalTopics/BigO.ptx
new file mode 100644
index 000000000..314e274f6
--- /dev/null
+++ b/pretext/AdditionalTopics/BigO.ptx
@@ -0,0 +1,202 @@
+
+
+ Big O Analysis
+
+
A common question that comes up when programming is: "How long will my program take to run?". Even if a program provides the correct output, if it takes
+ too long to finish then it is unacceptable. There is a problem here though, it's impossible to reliably say exactly how long a program will take to run.
+ It depends on too many things. The capabilities of the computer running the code, what else is running on the computer, and the size of the input are just
+ some of the things that would need to be considered.
+
+
+
To simplify this issue, we'll give up trying to estimate exactly how long a program will run, and instead look at the biggest factor that affect
+ existing code: the size of the input. If we wrote a program that ran for 60 seconds on 100 megabytes of input data, how should we expect the program to
+ react to 200 megabytes of input data? Maybe it would run in 120 seconds (twice the data for twice the run time)? Maybe it would still run in 60 seconds,
+ assuming that extra data isn't used. Or maybe the program would run for far longer. The issue is that we don't know what the relationship is between the size
+ of the input data and the behavior of the program.
+
+
This is where Big O Analysis comes in. Big O is a notation computer scientists use to describe the relationship between the size
+ of the input data and the behavior of the program. These terms are written like a mathematical function using the variable n. n as a variable represents the
+ size of the input data provided to the program. The Big O function tells us how n affects the time the program will take to complete.
+
+
Consider the example we had before. We have a program that takes 60 seconds to run on 100 megabytes of input data, we'd like to know (roughly)
+ how long the program might take to run on 200 megabytes of input data. If we know the run time of the program is the function f(n) = n^2, with n being
+ the size of the data, now we have enough information to make a guess. If n is doubled, then the time the program runs for will quadruple! (2*n)^2 = 4 * n^2.
+
+
The formal mathematical notation for Big O is denoted with a capital O (a big o!) followed by parentheses.
+ Inside of the O() is most commonly some term of n. In our previous example, we would say the program has O(n^2) behavior.
+
+
Different functions of n have different magnitudes, which helps us to quantify how quick or slow an algorithm is relative to the input size n.
+ From left to right, left being the quickest time and right being the slowest time, we typically see these complexities:
Big O is like a limit in that only the most significant terms matter as n gets bigger and bigger. We typically expect n to be very, VERY large because
+ small inputs aren't as strongly affected by time limits. If a program takes 0.001 seconds to run with most normal data, is it really a big deal if it takes 0.004
+ seconds on occasion? What if we were dealing with a program that had to run for a month though? Now that factor of four starts to hurt a lot more.
+
+
There is another important aspect that we have ignored up to this point: programs can often have wildly different behavior depending on their input.
+ Consider a contrived example:
In this program, the size of the input doesn't matter as much as whether the input string contains a letter "a" or not. If it does, the program runs forever.
+ If it doesn't, the program ends almost immediately. How do we reconcile this with our Big O notation? The answer is to be a pessimist. We adopt the assumption that
+ everything that can happen to slow down our program will happen. In the code above, we assume that the input ALWAYS will contain an "a". This assumption is broadly
+ known as the "worst case". Big O notation uses this assumption in every instance you will see it (at least in this class).
+
+
Let's look at some more examples:
+
+
+sum = 1 + 1
+print(sum)
+
+
+
This code has a Big O of O(1), also referred to as constant time. This is because the program does nothing with its input. In fact, it doesn't
+ even take input! Constant time operations are typically things in code which do not loop. A constant time program suggests it will always finish in a
+ consistent amount of time, no matter what happens.
+
+
Now, let's check out an example with a loop:
+
+
+def example_func(n):
+ for i in range(n):
+ print(i)
+
+
+
As you can see, this function simply prints 0 to n. Each print takes a little time, so a larger n means a longer program run time.
+ We denote the complexity of example_func as O(n),
+ because whether n = 100 or n = 10000000, as the complexity trends to infinity, it remains O(n).
+
+
In the last code example, O(n) was the complexity for all cases, because the loop always goes to n.
+
+
+
+
This figure shows complexities as a graph and which ones are considered "desirable" or at least "acceptable". Context mostly determines if these are "good" terms or not,
+ but do strive to never write something worse than O(n^3)!
+
+
It may be difficult to appreciate the implications of these terms when first seeing them. Let's say we have an algorithm with the following complexities, but they
+ all run with the same time (1 milliseconds) for n = 10. This table shows what will happen if we increase the size of the input:
+
+
+
+
+
+ n
+
+
+ O(log(n))
+
+
+ O(n)
+
+
+ O(n^3)
+
+
+ O(2^n)
+
+
+
+
+ 10
+
+
+ 1 ms
+
+
+ 1 ms
+
+
+ 1 ms
+
+
+ 1 ms
+
+
+
+
+ 11
+
+
+ 1 ms
+
+
+ 1.1 ms
+
+
+ ~1.3 ms
+
+
+ 2 ms
+
+
+
+
+ 20
+
+
+ 1.3 ms
+
+
+ 2 ms
+
+
+ 8 ms
+
+
+ 1 s
+
+
+
+
+ 100
+
+
+ 2 ms
+
+
+ 10 ms
+
+
+ 1 s
+
+
+ 10^16 years
+
+
+
+
+ 100000
+
+
+ 5 ms
+
+
+ 10 s
+
+
+ 31 years
+
+
+ :)
+
+
+
+
+
+
As you can see, what started off as a negligible difference exploded into a totally unacceptable time for larger input sizes applied to larger Big O terms. Examples like these are precisely why
+ computer scientists are so fixated on Big O. 100000 data points is not a lot of data. Large tech companies are often running code on billions or
+ trillions of data points, and anything less the most efficient code won't be able to run at-scale.
+
+
We will end this section with a disclaimer. We have only covered the bare basic concepts of Big O here today. If you continue to study computer science,
+ you'll have more opportunities to explore it in much more detail, including seeing the formal definition of Big O as well as learning how to determine the Big O of your own code.
+ For this specific class, we only ask you to be familiar with the notation of Big O and have a basic intuition behind what it communicates.
Have you ever seen all of the "hacker" 01010110101010s in the movies? As you might
+ know, this is called binary. While it's not actually how hacking works, binary is still the base of all computing.
+ Every word that you are reading right now was transmitted to your computer as a series of 1's and 0's. Although you won't
+ be typing 0's and 1's at a keyboard all day, binary is still useful to know.
+
+
Quick background: binary is a numbering system, just like decimal (the numbering system we normally use).
+ Decimal uses the digits 0-9, but binary only uses the digits 0 and 1, which are called bits.
+ In other words, binary is just a different way of counting.
+
+
Believe it or not, this is indirectly how you've been counting your entire life. For instance, in decimal numbering (base 10):
There are even more numbering systems, like hexadecimal and octal, but you only need to understand binary for this course.
+
+
Binary deals with powers of two (hence the name), reading from right to left and starting at 0.
+ If the bit is 0, it is "off" and the position is multiplied by 0; if the bit is 1, it is "on" and its
+ position in the number is the exponent with 2 as the base. Binary numbering is also called base 2
+ because of that. For instance:
Converting decimal to binary: A quick way to convert decimal to binary is to find the largest
+ factor of 2 that will go into the number, and concatenate 1 if it goes into the number; concatenate 0 if not. Subtract
+ the number from the running total and repeat until we hit 0. For instance:
+
+
Example: Convert 78 to binary
+
1. If we think about all of our powers of 2, 2^7 = 128 is too large (128 > 78), so we know 2^6 is where we'll start our number, and we need a 1 in that position. We now have: 1xxxxxx.
+
2. 78 - 64 = 14, which is our remainder from the last digit. 2^5 = 32 > 14, so we know 2^5 is a 0. We now have: 10xxxxx.
+
3. 78 - 64 = 14, which is our remainder from the last digit. 2^4 = 16 > 14, so we know 2^4 is a 0. We now have: 100xxxx.
+
4. 78 - 64 = 14, which is our remainder from the last digit. 2^3 = 8 < 14, so we know 2^3 is a 1 because it fits in! We now have: 1001xxx.
+
5. 78 - 64 - 8 = 6, which is our remainder from the last digit. 2^2 = 4 < 6, so we know 2^2 is a 1 because it fits in! We now have: 10011xx.
+
6. 78 - 64 - 8 - 4 = 2, which is our remainder from the last digit. 2^1 = 2 < 4, so we know 2^1 is a 1 because it fits in! We now have: 100111x.
+
7. 78 - 64 - 8 - 4 - 2 = 0, so we are done and can fill any remainders with a 0 bit.
+
Our final answer is: 1001110 (base 2)
+
+
+ Typically when we write binary, we'll see our bits in groups of 4, because our binary sequences are normally
+ some multiple of 4, like 8, 16, or 32. Because of this, we would add a leading zero and
+ write our previous answer as: 01001110 (base 2).
+
+
+
Converting binary to decimal: As mentioned above, you can simply look at each bit,
+ and add 2 to the power of its position if the bit is 1.
+
+
Like usual in math, there are a few different ways to arrive at one conclusion. These are not
+ the only ways to do conversions. If these explanations don't make sense to you, ask your instructor
+ or Google for their explanation.
+
diff --git a/pretext/AdditionalTopics/DataScience.ptx b/pretext/AdditionalTopics/DataScience.ptx
new file mode 100644
index 000000000..99569ff9f
--- /dev/null
+++ b/pretext/AdditionalTopics/DataScience.ptx
@@ -0,0 +1,53 @@
+
+
+ Data Science
+
+
Data science is a multidisciplinary field which combines computer science,
+ math, and other domains to answer questions using data.
+
+
As the world moves more and more towards storing and analyzing large amounts of data,
+ data science is a vital skill for you to be familiar with, whether you're a computer science major or not. It is also
+ a very common and useful application of programming, which is why we're discussing it in this class.
+
+
Data science is perhaps best defined by describing what data science looks like. The data science process consists of four steps:
+
+
+
Obtaining data
+
Cleaning the data
+
Exploring the data
+
Predicting unknowns
+
+
+
Obtaining the data: We live in a time where data is more abundant then ever before. Getting a hold of data can involve gathering it yourself,
+ purchasing it, or taking advantage of the many, many sites online now which have a plethora of data
+ available for free (and sometimes paid) use. if you are getting your data from some 3rd party, it will likely come in a .csv, .json, or SQL database format.
+
+
Cleaning the data: This can vary, but ultimately you need to prepare your data
+ in a way that makes it easily usable in the next steps. Often data starts out "noisy" or contains errors. In this step you may
+ fix things in the data, change missing data, or correct wrong data.
+
+
Cleaning is regularly considered the longest step in this process! Data can come in all sorts of different
+ formats now, with anomalies, with blanks, and so much more. It often depends on context and you own goals
+ what "fixing" data even means.
+
+
Exploring the data: Now that the data is prepared, we can do some analysis on it! As the term suggests, exploring the data is about coming to better
+ understand it. You often don't know what is interesting or useful about data when you first encounter it. You may need to do some sort of statistical
+ analysis to uncover the interesting aspects, or you may want to graph values and look for relationships and trends visually.
+
+
Predicting unknowns: Having come to understand the data better, you can now use it to create new knowledge. These days, this step typically involves
+ using machine learning models. These techniques can generally be split into three groups:
+
+
+
Supervised Learning: With supervised learning, we try to construct a model that describes the relationship between inputs and outputs (regularly
+ referred to as "labels"). Knowing what labels we want in advance is what makes a method "supervised". For example, we could create a model to guess when an email
+ is spam or not based on its contents; the label here is "spam" or "not spam". Or we could try to guess what the stock price will be for our favorite company based
+ on how it has performed in the last few weeks. The label here would be the predicted stock price.
+
Unsupervised Learning: Contrasting with supervised learning, with unsupervised learning we don't know the labels in advance. An example here could be
+ using social media data to automatically identify friend groups. We don't know in advance how many groups we'll find or what their nature will be. Because of this, it
+ can be harder to guess what kind of results unsupervised learning will produce.
+
Semi-Supervised Learning: Semi-supervised learning is an attempt to capture the best aspects of both supervised and unsupervised learning. With these
+ approaches we start with some data that has labels and also some data that doesn't. To use a previous example, we could take a collection of emails, only some of
+ which have been labeled as spam or not, and still try to construct a reliable method for identifying new emails as spam. If it goes well, then we've saved ourselves
+ a lot of time that would have otherwise been spent labeling emails.
A searching algorithm where you look through a sorted list in halves; an improvement upon linear search.
+
+
+ Big O Notation
+
A notation computer scientists use to describe the relationship between the size
+ of the input data and the behavior of the program, denoted with O() and some factor inside of the parenthesis.
+
+
+ constant time
+
A Big O time complexity of O(1).
+ comprehension
A specific Python construction that allows collection types to be created and filled with a single line of code.
-
+ dictionary
A collection of key-value pairs that maps from keys to values. The keys
can be any immutable type, and the values can be any type.
@@ -21,6 +34,10 @@
One of the pairs of items in a dictionary. Values are looked up in a
dictionary by key.
+
+ Linear search
+
A searching algorithm where you look through in a linear order (directly from start to end).
+ mapping type
A mapping type is a data type comprised of a collection of keys and
diff --git a/pretext/AdditionalTopics/More-BigO.ptx b/pretext/AdditionalTopics/More-BigO.ptx
new file mode 100644
index 000000000..e8b108fb7
--- /dev/null
+++ b/pretext/AdditionalTopics/More-BigO.ptx
@@ -0,0 +1,161 @@
+
+
+ Big O Simplification and Practice
+
+
One more important topic in Big O Analysis is simplification. We won't get too deep into the math, but here are a few general rules:
+
+
Constant time operations always simplify to O(1). For instance, O(3) and O(1000000) both simplify to O(1).
+
+
Added constants are ignored when a larger factor is around. For instance, O(n + 1) is just O(n).
+
+
Multiplication by a constant factor simplifies to the factor, such as O(3n) becoming O(n).
+
+
Added polynomials are ignored when a larger factor is around. For instance, O(n! + n) is just O(n!), or O(n^2 + n) is just O(n^2).
+
+
With nested loops, any inner loop factors are multiplied by the outer loop factor.
+
+
+
+
Example 1: Find the time complexity of this program. Be careful of the nested loop.
+
+
+ def example_func(n):
+ for i in range(n):
+ for j in range(n):
+ print(i * j)
+
+
+
+
+
+
+
O(1)
+
+
+ Incorrect; we have two nested loops here.
+
+
+
+
+
O(logn)
+
+
+ Not quite. You typically see O(logn) more often in search/sort algorithms.
+
+
+
+
+
O(n)
+
+
+ Incorrect; both loops (one of which is nested) depend on n.
+
+
+
+
+
O(n^2)
+
+
+ Correct! Both loops depend on n, and one loop is nested, which multiplies it by the parent factor.
+
+
+
+
+
+
+
+
Example 2: Find the time complexity of this program.
+
+
+def example_func(n):
+ for i in range(n):
+ for j in range(10000):
+ print(j)
+
+
+
+
+
+
+
O(1)
+
+
+ Not quite; we one loop going to n and one loop going to a constant time.
+
+
+
+
+
O(logn)
+
+
+ Not quite. You typically see O(logn) more often in search/sort algorithms.
+
+
+
+
+
+
+
+ Not quite, since n is an arbitrary user inputted value.
+
+
+
+
+
O(logn)
+
+
+ Not quite. You typically see O(logn) more often in search/sort algorithms.
+
+
+
+
+
O(n)
+
+
+ Correct! We're going to n in this loop.
+
+
+
+
+
O(n^2)
+
+
+ Incorrect. We only have one loop going to n.
+
+
+
+
+
diff --git a/pretext/AdditionalTopics/SearchSortAlgorithms.ptx b/pretext/AdditionalTopics/SearchSortAlgorithms.ptx
new file mode 100644
index 000000000..5f8dbfb4d
--- /dev/null
+++ b/pretext/AdditionalTopics/SearchSortAlgorithms.ptx
@@ -0,0 +1,50 @@
+
+
+ Search and Sort Algorithms
+
+
A major part of computer science is studying algorithms. There are two types of algorithms
+ that are spoken about very often: search and sort. Not only are they great
+ for learning about Big O and algorithms, but they're very applicable in the real world.
+
+
As the internet grows and the data we store grows, companies have to wrestle with the large amounts of data
+ they have. Imagine if you're Google and you're looking for one user out of one billion.
+ Now imagine you need to do that a thousand times a minute, with people doing it at the same time.
+ The code you write and the algorithms you use become massively important to how quickly
+ these operations can be done.
+
+
Linear search is the most basic searching algorithm, and the most intuitive.
+ Quite simply, you look through whatever you're considering in a linear order; from first to last.
+ This could be a stack of papers, or it could be a list in Python.
+
+
+
+# a program which finds 10 in my list, linearly
+my_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+for element in my_list:
+ if element == 10:
+ print('found 10!')
+ break
+
+
+
+
Linear search has a best case complexity of O(1), average case of O(n), and worst case of O(n).
+ Remember from the Big O section: in the best case, the element we're looking for is the first element. But in the
+ average and worst cases, we will have to look through some n elements.
+
+
Binary search is an improvement upon linear search. Binary search splits the searched list in half,
+ and if the number we're searching for is less than that number, we know it must be in the left half of the list;
+ if it's greater, we know it must be in the right half of the list, and we can repeat this process on smaller portions of the list until we find the number.
+
+
Binary search has a best case complexity of O(1), average case of O(logn), and worst case of O(logn).
+
+
However, there's a catch: for binary search to work, the list must be sorted! This is where sorting algorithms can come in. Sorting will not be covered in
+ this class, but we will describe one sorting algorithm for those that are curious.
+
+
Selection sort is a simple sorting algorithm. The idea is that we take the smallest element and swap it with the leftmost element,
+ and then the leftmost element becomes the sorted list. We repeat this process, and the sorted portion of the list grows in size each time, so we're only
+ adding elements from the nonsorted portion of the list to the end of the sorted part of the list.
+
+
The time complexity of selection sort is O(n^2) in every case.
+
+
Some other common sorting algorithms include Bubble Sort and Insertion Sort, but we will leave those for another class.
None, or the NoneType, is a type which represents the absence of a value.
+ But let's take a step back and think: why is this useful?
+
+
In Python, sometimes we don't want to return anything from a function. However, when we don't
+ explicitly return anything from a function, Python will implicitly return None.
+ You could also explicitly return None from a function or return a value,
+ and then you would have to check if the function returned something or not.
+
+
For the purposes of this class, you should just understand when None appears and why.
+
+
Most commonly when students are learning about strings and lists, us educators see a similar issue, which links back
+ to sections on mutability. Strings are immutable and lists are mutable, remember?
+
+
When we want to modify a string, we must reassign it, because it's immutable:
+
+
+print(my_list[0])
+~~~~~~~^^^
+TypeError: 'NoneType' object is not subscriptable
+
+
+
+
Frustratingly, your code actually did exactly what you told it to. List functions modify the list directly, because
+ lists are mutable. Therefore, their functions (such as .append(element)) don't return anything.
+
+
But now we know why: append is actually implicitly returning None. This means that in the previous example, we reassigned my_list
+ to None, and then we tried to list access element 0 of None, which caused the 'not subscriptable' error, because None isn't a list
+ and can't have list access done to it.
+
+
The solution is simple: don't reassign the list when calling list functions.
If you remember nothing else, remember: strings get reassigned, lists don't. This is because
+ strings are immutable; lists are mutable and their functions don't return anything (they implicitly return None!).
+
+ You may be wondering how to tell the difference between functions that return something or not. Sometimes
+ the name of the method can be a hint (e.g. if it has "set" in the name, it probably won't return, whereas "get" will).
+ If that doesn't help or you're still curious, you should reference the documentation (whether it's official Python
+ documentation or for a library). No shame in looking it up!
+
+
You won't be tested on the information below, but read on for some interesting thoughts on this.
+
+
If you've been around any other programming languages, you may have heard of equivalent ideas like
+ null, NULL, nullptr, nil, and more. This is such a universal concept
+ in programming and is hugely frustrating to many programmers as it often represents something that went wrong.
+
+
Fun (or depressing) fact -- the inventor of null actually regrets his invention:
+
+
+ I call it my billion-dollar mistake... At that time, I was designing the first comprehensive type system for references in an object-oriented language. My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn't resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years.
+
+
+
+ - Tony Hoare
+
+
+
Despite this, None, null, and nil don't seem to be going anywhere anytime soon. :)
+
diff --git a/pretext/Lists/toctree.ptx b/pretext/Lists/toctree.ptx
index 96b9c0a70..ef9892fee 100644
--- a/pretext/Lists/toctree.ptx
+++ b/pretext/Lists/toctree.ptx
@@ -14,6 +14,7 @@
4
4
4
+4
4
4
diff --git a/pretext/PythonModules/Packages.ptx b/pretext/PythonModules/Packages.ptx
new file mode 100644
index 000000000..804312967
--- /dev/null
+++ b/pretext/PythonModules/Packages.ptx
@@ -0,0 +1,44 @@
+
+
+ Packages and Dependencies
+
+ You won't ever need to deal with dependencies in this course unless you are adding modules to your final project. Nonetheless, using packages
+ (a package is just a collection of Python modules) is a common practice in Python programming that you should at least be aware of.
+
+
One key tenant of computer science (or anything, for that matter) is that we don't want to reinvent
+ the wheel if we don't have to. A lot of very smart people have made very useful code, so why not use it?
+
+
The is a website that maintains packages, or code that other people
+ have written for our use. You might also hear the term dependencies, which describes essentially the same thing: code
+ that our code depends on.
+
+
PyPI can be accessed with pip, which is the command that you will use when installing dependencies. Pip should come
+ preinstalled with most Python installations on Mac and Windows.
+
+
Some common packages include: pytest (for testing your code), python-dateutil (for working with dates), flask (for making websites), and more.
+
+
Some common packages for data science include numpy, matplotlib, scipy, pandas and more.
+
+
But this is all sounding like a lot to keep track of, right? How can we ensure consistency between
+ versions installed on different people's computers?
+
+
requirements.txt is a file we can specify for others to be able install the dependencies
+ (which is needed to run our code), since others may not have our dependencies installed.
+
+
The following code represents a requirements.txt file that specifies numpy as a dependency:
+
+
+numpy==1.26.2
+
+
+
+
Note that dependencies are not installed immediately. For someone to install the requirements which you specify,
+ they would run the command: pip install -r requirements.txt.
+
+
If you're unsure what version of a dependency you have installed, you can run the command: pip show DEPENDENCY, like pip show numpy.
+ Somewhat ironically, there are also packages that can autogenerate a requirements.txt file for you.
+
+ One additional tip worth mentioning is to always specify the bare minimum requirements your code needs to work.
+ Dependencies normally have dependencies of their own, so we want to minimize the install time and space taken up
+ when someone is installing your program's requirements.
+
diff --git a/pretext/PythonModules/toctree.ptx b/pretext/PythonModules/toctree.ptx
index 77275913f..896c0c70a 100644
--- a/pretext/PythonModules/toctree.ptx
+++ b/pretext/PythonModules/toctree.ptx
@@ -5,6 +5,7 @@
4
4
4
+4
4
4
diff --git a/pretext/Selection/Glossary.ptx b/pretext/Selection/Glossary.ptx
index 45f9621a2..1c0683c58 100644
--- a/pretext/Selection/Glossary.ptx
+++ b/pretext/Selection/Glossary.ptx
@@ -69,5 +69,10 @@
One program structure within another, such as a conditional statement
inside a branch of another conditional statement.
+
+ Pseudocode
+
A mix of English and code (in our case, Python) that
+ programmers use to plan out their programs.
With the introduction of conditionals and branching, our programs are about to become more complex on average. This is a good time to introduce a technique
+ that will help you plan and structure your programs before you start writing the more complex code. That technique is to use pseudocode.
+
+
Pseudocode is a mix of English and code (in our case, Python) that
+ programmers use to plan out their programs.
+
+
Writing pseudocode can be helpful for reasons such as:
+
+
It's quicker to write than actual code!
+
It's readable to more people than actual code, and can still be critiqued like regular code.
+
It can help you to take on a large or confusing programming task.
+
It can help you to document your code with comments for yourself and others' readability.
+
+
+
There isn't necessarily a right or wrong syntax for pseudocode (except wrong would be if you just wrote the program!).
+ Your pseudocode and language will probably look different from this, but should be along the same lines.
+
+
Take the following prompt for a problem:
+
+
+ Write a program that takes in a fraction in the format NUMERATOR/DENOMINATOR
+ from the user and outputs the quotient and the remainder.
+ If the denominator is 0, print out an error message; if the denominator is anything else,
+ let the user run the program normally.
+
+
+
We can approach this problem first by writing the following pseudocode:
+
+
+take user input for fraction
+split the user input by "/"
+make a variable for numerator, type convert to int
+make a variable for denominator, type convert to int
+if the denominator is 0,
+ print an error message
+otherwise
+ make a variable for the numerator divided by denominator
+ make a variable for the numerator mod denominator
+ print out both variables
+
+
+
+
As you can see, this is basically just a high level outline of your program. It may help you
+ better see the control flow of your program, or even remind you to do the small things, like
+ converting your string input to an integer if necessary.
+
+
This pseudocode can then be more readily converted to Python:
This won't be something you see often, but let's reverse engineer and see what
+ existing Python code might look like in pseudocode.
+
+
+
+character = input()
+if character == "Yoda":
+ print("No! Try not. Do. Or do not. There is no try.")
+elif character == "Han Solo":
+ print("Never tell me the odds!")
+elif character == "Obi Wan Kenobi":
+ print("Use the Force, Luke.")
+else:
+ print("Character not found!")
+
+
+
+
We could write the following pseudocode for this program:
+
+
+take user input for a Star Wars character
+if the character is Yoda, print "No! Try not. Do. Or do not. There is no try."
+if the character is Han Solo, print "Never tell me the odds!"
+if the character is Obi Wan Kenobi, print "Use the Force, Luke."
+in all other cases, print that the character wasn't found
+
+
+
+
As you may start to notice, Python is so close to the English language that pseudocode can often
+ be quickly translated into code.
+
+
Feel free to use pseudocode on exams (for planning before writing code) and in your actual programs.