5
\$\begingroup\$

This is a problem set from the MIT online course :

Suppose you want to set a particular goal, e.g. to be able to afford the down payment in three years. How much should you save each month to achieve this? In this problem, you are going to write a program to answer that question. To simplify things, assume: 3

  1. Your semi­annual raise is .07 (7%)
  2. Your investments have an annual return of 0.04 (4%)
  3. The down payment is 0.25 (25%) of the cost of the house
  4. The cost of the house that you are saving for is $1M.

You are now going to try to find the best rate of savings to achieve a down payment on a $1M house in 36 months. Since hitting this exactly is a challenge, we simply want your savings to be within $100 of the required down payment.

In ps1c.py, write a program to calculate the best savings rate, as a function of your starting salary.

  • You should use bisection search to help you do this efficiently.
  • You should keep track of the number of steps it takes your bisections search to finish.
  • You should be able to reuse some of the code you wrote for part B in this problem.

Because we are searching for a value that is in principle a float, we are going to limit ourselves to two decimals of accuracy (i.e., we may want to save at 7.04% ­­ or 0.0704 in decimal – but we are not going to worry about the difference between 7.041% and 7.039%).

This means we can search for an integer between 0 and 10000 (using integer division), and then convert it to a decimal percentage (using float division) to use when we are calculating the current_savings after 36 months. By using this range, there are only a finite number of numbers that we are searching over, as opposed to the infinite number of decimals between 0 and 1. This range will help prevent infinite loops.

The reason we use 0 to 10000 is to account for two additional decimal places in the range 0% to 100%. Your code should print out a decimal (e.g. 0.0704 for 7.04%). Try different inputs for your starting salary, and see how the percentage you need to save changes to reach your desired down payment.

Also keep in mind it may not be possible for to save a down payment in a year and a half for some salaries. In this case your function should notify the user that it is not possible to save for the down payment in 36 months with a print statement. Please make your program print results in the format shown in the test cases below.

here is how I managed to do this:

############## Inilize varibles ####################

current_savings = 0
salary = 201
intial_salary = salary
total_cost = 7200

#add in the bank return and the semi annual rasie 
# and don't forget to inilaize the varibles with each loop
# also add a way for your program to escape the infinite loop when it's not possible 
# to save for the total cost in two years 

########################## Rate #####################
low = 0
high = 1

rate = (low + high) / 2

print ("rate =", rate)

######################################################




while True :
########### re-inilaizing varibles for a new loop ######
# rate is being re-iniliazed first because the deposit amount depends on it ###
    rate = (low+high)/2
    salary = intial_salary
    deposit = rate * salary
    current_savings = 0
    bank_return = 0
##########################################################

####### looping the savings vs total_cost calculations 36 times for 36 months ##########


    print ("rate=", rate)
    for var in range (1,38) :
        current_savings += deposit
        bank_return = current_savings * 0.04 / 12
        current_savings += bank_return
        print ("current_savings=",current_savings) 
###### semi_annual_raise #######################

        if var % 6 == 0 :
            print (var)
            print ("salary=" , salary )
            salary = salary + (salary * 0.07)
            deposit = rate * salary


###########################################################

##### modifying the rate value based on the diffrence between the ####
##### current_savings and total_cost ############################

    if current_savings < total_cost :
        low = rate
    elif current_savings > total_cost:
        high = rate       


# two ways to break the loop , first is that current_savings is equal to total_cost and in this case the rate is the pefect match
# the second way is that the rate is alreay 1 (whole salary) but still the current_savings are not equal to the total_cost so the
# the break is there to escape the infinite loop


#    elif current_savings == total_cost : #( was working just fine until i introduced the semi_annual raise to the code )
    if abs(current_savings - total_cost ) < 0.000001 : 
        break
    if rate == 1 : #and current_savings < total_cost : ( an additonal unndeeded condition , kept here in case needed later )
        print ("not possible")
        break



print ("current_savings=",current_savings) 
print (rate * salary * 36)
print ("rate=", rate)

Can you please tell me how this code can be improved?

\$\endgroup\$
4
  • 4
    \$\begingroup\$ This is not your first question here, but nevertheless let me remind you of some things: 1. The title should state what to programm accomplishes. 2. We can only review code that you have written or that is maintained by you.. So reviewing the GitHub piece (where you should at least link to the source to give proper credit!) is likely off-topic. \$\endgroup\$
    – AlexV
    Commented Sep 29, 2019 at 17:09
  • 2
    \$\begingroup\$ discussed in meta: codereview.meta.stackexchange.com/questions/9353/… \$\endgroup\$
    – dfhwze
    Commented Sep 29, 2019 at 17:27
  • 2
    \$\begingroup\$ I did edit the question to include credits to the original code owner, if this kind of practice was deemed to be off-topic then i will edit the second set of code off the question. As for the title to include what the program should do; I did try that to no avail, due to the limit of characters in the title. \$\endgroup\$
    – Elbasel
    Commented Sep 29, 2019 at 17:32
  • 4
    \$\begingroup\$ I removed the referenced code and updated the question as per the meta response. \$\endgroup\$
    – Elbasel
    Commented Sep 29, 2019 at 19:45

2 Answers 2

2
\$\begingroup\$

Magic Numbers

for var in range (1, 38):

What is 1 and 38 supposed to represent? You should make it clear what these are by declaring in variables/CONSTANTS.

Spacing

print (var)
if current_savings < total_cost :
rate = (low+high)/2

should instead be

print(var)
if current_savings < total_cost:
rate = (low + high) / 2

You don't separate () from their function names, : from their statements, and arithmetic operators should be spaced out to increase readability.

Printing

Instead of this

print ("current_savings=",current_savings)

use an f"" string to directly incorporate your variables into the string, like so:

print(f"current_savings={current_savings}")

Naming

Constants like

intial_salary = salary
total_cost = 7200

should be uppercase to show that they are:

INITIAL_SALARY = salary
TOTAL_COST = 7200
\$\endgroup\$
2
  • \$\begingroup\$ So basically we're saving up money for 36 months , this is what the problem set states. I do get the spacing and I will work on it, thanks ! But I don't see why these variables should be uppercase? \$\endgroup\$
    – Elbasel
    Commented Oct 1, 2019 at 16:58
  • \$\begingroup\$ @Elbasel These are variables that never change. You use INITIAL_SALARY to reset the value of salary, and you use TOTAL_COST to determine savings rate. Since you don't want these to be changed mid program, they should be UPPERCASE. This lets you know not to change them after declaring them at the top of your program. \$\endgroup\$
    – Linny
    Commented Oct 1, 2019 at 19:03
2
\$\begingroup\$

This may be but a small point, but this:

salary = 201
intial_salary = salary

Makes more sense the other way around:

INITIAL_SALARY = 201
salary = INITIAL_SALARY

The initial is there first, or it wouldn't be the initial value. Setting the initial after the current value seems, odd.

For short scripts like this, it doesn't matter much. But debugging & maintainability becomes a little easier if you put your declarations and assignments in an order that makes sense. It's a good habit to get into early.

Also, the following has the potential for disaster:

if abs(current_savings - total_cost ) < 0.000001 : 
    break
if rate == 1 :
    print ("not possible")
    break

What if neither becomes true? You're in a while True loop. It's going to run forever if by some bug neither of the conditions become true (those are the only options your program has to break). You may want to consider a fail-safe of sorts, or change your loop altogether. while loops often look like an easy way out, but in Python, there's often a better way.

\$\endgroup\$
1
  • \$\begingroup\$ Thanks for the input, but one value HAS to eventually be true, since this is bisectional search and eventually the rate is going to be equal to 1. Also , the initial salary value is there just so that I can re-intialize the salary variable after each loop so it I think it makes more sense to have it as intitial salary. \$\endgroup\$
    – Elbasel
    Commented Oct 1, 2019 at 16:55

Not the answer you're looking for? Browse other questions tagged or ask your own question.