Python Forum

Full Version: Another infinite loop
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
The given problem: use bisectional search to find the minimum monthly payment to pay off debt after 12 payments (slight.
Assume that the interest is compounded monthly according to the balance at the end of the month (after the payment for that month is made).

annualInterestRate=.1 # i used these numbers soley as placeholders to test the program
balance=100 # i used these numbers soley as placeholders to test the program
monthlyInterestrate=annualInterestRate/12
balance_initial=balance
lowerbound=(1/12)*balance # the upperbound and lowerbound were defined in the given problem for us.
upperbound=balance*(1+monthlyInterestrate)**(12)/12 
monthlyPayment=(upperbound+lowerbound)/2
while balance!=0:
    for i in range(12):
        balance=balance-monthlyPayment + (balance-monthlyPayment)*monthlyInterestrate
    if balance>0:
            monthlyPayment=(upperbound+monthlyPayment)/2
    if balance<0:
            monthlyPayment=(lowerbound+monthlyPayment)/2
    balance=balance_initial
print('Lowest Payment: ' + str(round(monthlyPayment, 2)))
Is there something wrong with my bisectional search? I've been looking at it for some time and I don't see how this could give me an infinite look; if the monthlyPyament is too large it is lowered, and if it is too small it is raised until the minimum balance is found.
Line 15 is resetting balance to 100 at the end of every loop, so it can never reach 0.

Edit: I ran a test without that and you are still going to have problems. Balance passes zero and goes way down, never reaching 0 exactly. You might want to test if the balance is close enough (like less than a penny from 0). Also, in a bisectional search you are changing the upper or lower bound and picking the middle repeatedly. You're not changing the bounds, just the monthly payment. And once the balance gets to zero, line 14 continually increase the monthly payment.
I edited my code to
annualInterestRate=.1
balance=100
monthlyInterestrate=annualInterestRate/12
balance_initial=balance
lowerbound=(1/12)*balance
upperbound=balance*(1+monthlyInterestrate)**(12)/12
monthlyPayment=(upperbound+lowerbound)/2
while balance>-.00001 and balance<.00001:
    for i in range(12):
        balance=balance-monthlyPayment + (balance-monthlyPayment)*monthlyInterestrate
    if balance>0:
            monthlyPayment=(upperbound+monthlyPayment)/2
    if balance<0:
            monthlyPayment=(lowerbound+monthlyPayment)/2
    
print('Lowest Payment: ' + str(round(monthlyPayment, 2)))
but now everything is off by a small amount.
For instance, a balance of 320000 and an annualInterestRate of .2 should yield "Lowest Payment: 29157.09" but I'm getting 29591.88

I'm quite confused as to why this still isn't working.
You never execute the while loop - check what conditions you have. While loop will be executed if balance is between -0.00001 and 0.00001.Is it the case with starting balance of 320 000?
Buran is right. You need what is often called an until loop. While it is not explicitly supported in Python, you can do one this way:

while True:
    # do stuff
    if condition:
        break
That is, check the condition at the end of the loop, rather than use a standard while that will check it at the beginning of the loop.
or use just one condition, e.g.
while balance > 10**-10: # very very very small number
Another point to be strict - working with money requires 2 decimal points precision (i.e. in real life you cannot substract 150.1234321 from your balance, you will substract 150.12). you may want to check decimal module for this purpose.
I guess it is late enough to be early.
Fixed it, thanks for all your help. In the end I used this.
monthlyInterestrate=annualInterestRate/12
balance_initial=balance
lowerbound=(1/12)*balance
upperbound=balance*(1+monthlyInterestrate)**(12)/12
while balance >.0001 or balance<-.0001:
    balance=balance_initial
    monthlyPayment=(upperbound+lowerbound)/2
    for i in range(12):
        balance=balance-monthlyPayment + (balance-monthlyPayment)*monthlyInterestrate
    if balance>0:
            lowerbound=monthlyPayment
    if balance<0:
            upperbound=monthlyPayment
     
print('Lowest Payment: ' + str(round(monthlyPayment, 2)))