Homework 2

Due: Tuesday, February 6 at 11:59 pm

Submission: On Courseworks

Instructions

Please read the instructions carefully. An incorrectly formatted submission may not be counted.

There are two parts to this assignment. In the first part, you will write pseudocode for several algorithms. Your submission should be in a single plain text file called part1.txt. You can create a plain text file with Textedit on Mac, or Notepad on Windows. Please ensure your submission is a plain text file, and not a rich text file/word/pages/other.

In the second part, you will write Python code to implement several of these algorithms. You can do your programming in the REPL, IPython, Jupyter, or Spyder, but your submission should be in a single .py file called part2.py.

To submit, put part1.txt and part2.py in a folder called uni-hw2 (so for me this would be tkp2108-hw2). Then compress this folder into a .zip file. For most operating systems, you should be able to right click and have a “compress” option in the context menu. This should create a file called tkp2108-hw2.zip (with your uni). Submit this on courseworks.

Here is an example submission:

Part 1:

Part 2:

Folder:

Part 1

In part 1, we will be implementing pseudocode to solve a handful of problems. Recall the following guidelines around pseudocode:

Question 1

Implement pseudocode for calculating the running average of numbers. While the user continues to input numbers (e.g. in a loop), keep the running average. When the user stops, emit the average of the numbers input.

Question 2

Given a list of integers as an input, write pseudocode to replace each element except the first and last by the smaller of its neighbors. Be careful, you should ensure to compare each elements' neighbors in the original list, not the modifications you make. This problem relates to important concepts called mutability and side effects which we will return to in a future lecture.

Question 3

On social media, there is a lot of misinformation about income inequality and taxation. For question 3, we will implement a progressive tax calculator. Given a number as input, calculate the total federal income tax using the 2023 tax brackets:

You may find it helpful to implement a helper function similar to the one we used in the Roman Numeral converter from class.

Part 2

In part 2, we will be converting pseudocode to proper Python code.

Question 1

Implement the Euclidean Algorithm for determining the greatest common divisor of two integers.

To do this, define and implement a python function similar to the following:

def gcd(a, b):
    '''Determine the GCD of a and b using the Euclidean Algorithm'''
    ...

Once implemented, you can test this function by calling it from your python interpreter (REPL, IPython, Jupyter, or Spyder):

print(gcd(5, 3))
print(gcd(15, 5))
print(gcd(27, 9))
print(gcd(1, 2))
print(gcd(13, 31))

When you’re satisfied that your gcd function works properly, include just the function definition in part2.py.

Question 2

Implement the running average function from part 1.

To do this, define and implement a python function similar to the following:

def runningAverage():
    user_input = input("input a number")

    while user_input:
        ...

        user_input = input("input another number")

Question 3

Implement your progressive tax calculator from part 1.

To do this, define and implement a python function similar to the following. Again, you may find it helpful to implement helper functions.

def taxCalculator(total_income):
    '''This function should return the total tax amount based on the total_income'''
    ...

Notes

A lot of people were structuring their tax calculator as a sequence of increasingly complicated calculations, e.g.

if 0 <= salary <= 9950:
    return salary * .1
elif 9950 <= salary <= 40525:
    return 9950 * .1 + (salary - 9950) * .12
...

This is totally fine, but it can lead to some complicated code. There is a simpler way of accomplishing the same effect. If we think of each tax bracket independently, we either pay the full burden, a partial burden, or no burden. Looking at visual diagrams of this, each tax bracket is a block on the number line:

Since each bracket contributes independently to our overall tax burden, we can encapsulate all the logic for a tax bracket into a single helper function:

def calculateTaxForBracket(salary, low, high, rate):
    ...

We then have 3 cases: either make more than the max of the bracket, in which case we pay the full burden:

So in code:

def calculateTaxForBracket(salary, low, high, rate):
    if salary > high:
        return (high - low) * rate

Or, we make less than the high of the bracket but more than the low, in which case we have a partial burden:

In code:

def calculateTaxForBracket(salary, low, high, rate):
    if salary > high:
        return (high - low) * rate
    if salary > low:
        return (salary - low) * rate

Otherwise, we make less than the low, so there’s no burden for the bracket:

In code:

def calculateTaxForBracket(salary, low, high, rate):
    if salary > high:
        return (high - low) * rate
    if salary > low:
        return (salary - low) * rate
    return 0

We can test our bracket calculator, and validate that given a bracket and a salary, it correctly gives us back the tax burden for that bracket:

>>> def calculateTaxForBracket(salary, low, high, rate):
...     if salary > high:
...         return (high - low) * rate
...     if salary > low:
...         return (salary - low) * rate
...     return 0
...
>>> calculateTaxForBracket(9950, 0, 9950, .10)
995.0
>>> calculateTaxForBracket(10000, 0, 9950, .10)
995.0
>>> calculateTaxForBracket(10000, 9951, 40525, .12)
5.88
>>> calculateTaxForBracket(1_000_000, 523_601, float("inf"), .37)
176267.63
>>>

To calculate the total burden, we can then just sum up the burden for the individual tax brackets.

Example Tax Numbers

from part2 import taxCalculator

for salary in (0, 1_000, 10_000, 100_000, 1_000_000):
    tax = taxCalculator(salary)
    print(f"Salary: ${salary:> 8}\tTax: ${int(tax):> 8}\t\tEffective Rate: {round(tax/salary*100, 2) if salary else 0}%")
Salary: $       0    Tax: $       0        Effective Rate: 0%
Salary: $    1000    Tax: $     100        Effective Rate: 10.0%
Salary: $   10000    Tax: $    1000        Effective Rate: 10.0%
Salary: $  100000    Tax: $   17399        Effective Rate: 17.4%
Salary: $ 1000000    Tax: $  330331        Effective Rate: 33.03%