2013-03-18 13 views
8

Próbuję obliczyć minimalne miesięczne płatności, aby spłacić pożyczkę przy użyciu następujących:obliczeniowe najniższe miesięczne płatności przy użyciu wyszukiwania bisekcji w python

balance = 999999 
annualInterestRate = .18 
monthlyInterestRate = annualInterestRate/12 

balanceCOPY = balance 

#Bisection search parameters 

lo = balance/12 
hi = (balance*(1+monthlyInterestRate**12))/12 
epsilon = .01 

guess = (lo + hi)/2 

while True: 
    for month in range(1,13): 
     balance = balance - guess 
     balance = balance + (monthlyInterestRate*balance) 

    if balance > 0 and balance > epsilon: 
     lo = guess 
     balance = balanceCOPY 
    elif balance < 0 and balance < -epsilon: 
     hi = guess 
     balance = balanceCOPY 
    else: 
     print('Lowest payment: ',str(round(guess,2))) 
     break 

    guess = (lo + hi)/2 

Jednak wydaje się tkwić w jakiejś nieskończona pętla, w której moja zmienna guess nie jest aktualizowana. Jak mogę wyrwać się z nieskończonej pętli i zaktualizować moją zmienną guess?

Problem był w mojej matematyce. Chciałem powiedzieć:

hi = (balance*(1+monthlyInterestRate)**12)/12 

Dziękuję za całą pomoc wszystkim!

+0

Jakie jest Twoje pytanie? (I "+1 dla [SSCCE] (http://SSCCE.org)"). –

+0

Czy próbowałeś wydrukować wszystkie zmienne podczas każdej iteracji pętli i sprawdzając, czy jedna z nich nie jest aktualizowana? Również skąd czerpiesz ten algorytm? – placeybordeaux

+0

Wiesz, że istnieją formuły do ​​tego, prawda? http://en.wikipedia.org/wiki/Compound_interest#Simplified_calculation –

Odpowiedz

3

Aby dowiedzieć się błędy jak ten, dobrym sposobem jest po prostu dodać trochę drukiem, na przykład, dodałem następujące w kodzie:

print(balance, lo, hi, guess) 

wtedy zobaczyć, co się dzieje, można dowiedzieć się, co jest dziać się. Jak się okazuje:

hi = (balance*(1+monthlyInterestRate**12))/12 

oblicza górną granicę, która jest zbyt niska. Może chodziło:

hi = (balance*(1+monthlyInterestRate*12))/12 
+1

Dzięki za wskazanie tej części z mojego programu. Nie mogę uwierzyć, że zawsze tęsknię za czymś głupim. Miałem na myśli hi = (saldo * (1 + miesięcznyInterestRate) ** 12)/12 –

3

zmieniłem swój kod do tego:

balance = 999999 
annualInterestRate = .18 
monthlyInterestRate = annualInterestRate/12 

balanceCOPY = balance 

#Bisection search parameters 

low = balance/12 
high = (balance * (1 + monthlyInterestRate ** 12))/12 
epsilon = .01 

print "starting high and low guesses" 
print "high: %s" % high 
print "Low: %s" % low 
print "\n" 

guess = (low + high)/2 

for i in range(5): 

    print "Type of balance: %s" % type(balance) 
    print "Balance is: %s" % balance 
    print "Low: %s" % low 
    print "High: %s" % high 
    print "Guess: %s" % guess 

    print "monthly interest %s" % (monthlyInterestRate * balance) 

    for month in range(1, 13): 
     balance -= guess 
     balance += monthlyInterestRate * balance 

    print "balance after %s" % balance 

    if balance > 0 and balance > epsilon: 
     print "Change low" 
     low = guess 
     balance = balanceCOPY 
    elif balance < 0 and balance > -epsilon: 
     high = guess 
     balance = balanceCOPY 
    else: 
     print('Lowest payment: ', str(round(guess, 2))) 
     break 

    guess = (low + high)/2 

    print "\n" 

Kilka uwag: zmieniłem "hi" i "lo" na "wysokie" i "niskie". Lepiej nie skracać nazw zmiennych, ponieważ skrócone nazwy zmiennych są mniej czytelne.

Dodałem instrukcje debugowania pokazujące wartości różnych zmiennych.

Tu był wynikiem prowadzenia wyżej:

starting high and low guesses 
high: 83333.25 
Low: 83333 


Type of balance: <type 'int'> 
Balance is: 999999 
Low: 83333 
High: 83333.25 
Guess: 83333.125 
monthly interest 14999.985 
balance after 92550.599997 
Change low 


Type of balance: <type 'int'> 
Balance is: 999999 
Low: 83333.125 
High: 83333.25 
Guess: 83333.1875 
monthly interest 14999.985 
balance after 92549.7726951 
Change low 


Type of balance: <type 'int'> 
Balance is: 999999 
Low: 83333.1875 
High: 83333.25 
Guess: 83333.21875 
monthly interest 14999.985 
balance after 92549.3590442 
Change low 


Type of balance: <type 'int'> 
Balance is: 999999 
Low: 83333.21875 
High: 83333.25 
Guess: 83333.234375 
monthly interest 14999.985 
balance after 92549.1522187 
Change low 


Type of balance: <type 'int'> 
Balance is: 999999 
Low: 83333.234375 
High: 83333.25 
Guess: 83333.2421875 
monthly interest 14999.985 
balance after 92549.048806 
Change low 

Z tego widać, że niska wartość jest zbieżne do swojej wysokiej wartości. Innymi słowy, początkowa wysoka wartość nie jest wystarczająco wysoka. Gdy będą miały tę samą wartość, pętla nigdy niczego nie zmieni i będzie trwać wiecznie.

myślę wiersz:

elif balance < 0 and balance < -epsilon: 

powinien brzmieć:

elif balance < 0 and balance > -epsilon: 

ponieważ myślę, że chcesz równowagi między 0 i -epsilon zamiast mniej niż -epsilon

Ponadto, jak @WinstonEwert zauważyć:

hi = (balance*(1+monthlyInterestRate**12))/12 

powinny być

hi = (balance*(1+monthlyInterestRate)**12)/12 
+0

Upewnij się, że poprawisz 'saldo eliftu <0 i saldo <-epsilon:'. Teraz sprawdzasz, czy saldo jest mniejsze od 0 i mniejsze niż -0,01. Zauważ, że -100000000000 pasuje do tych kryteriów. – mydogisbox

5

Myślę, że to rozwiązanie powinno działać,

balance = 999999 
annualInterestRate = 0.18 

monthlyInterestRate = annualInterestRate/12 
lowerBound = balance/12 
upperBound = (balance * (1 + annualInterestRate/12) ** 12)/12 
originalBalance = balance 
lowestBalance = 0.01 # Error margin e.g. $0.01 

# Keep testing new payment values until the balance is +/- lowestBalance 
while abs(balance) > lowestBalance: 
    # Reset the value of balance to its original value 
    balance = originalBalance 
    # Calculate a new monthly payment value from the bounds 
    payment = (upperBound - lowerBound)/2 + lowerBound 

    # Test if this payment value is sufficient to pay off the entire balance in 12 months 
    for month in range(12): 
     balance -= payment 
     balance *= 1 + monthlyInterestRate 

    # Reset bounds based on the final value of balance 
    if balance > 0: 
     # If the balance is too big, need higher payment so we increase the lower bound 
     lowerBound = payment 
    else: 
     # If the balance is too small, we need a lower payment, so we decrease the upper bound 
     upperBound = payment 

# When the while loop terminates, we know we have our answer! 
print "Lowest Payment:", round(payment, 2) 
4

Przede wszystkim, jeśli robisz mITX ćwiczenia i zakończone poprzedniego testu (tak, aby zwiększyć 10 w odgadnięcia) jesteś małym krokiem, aby to zdobyć. Po prostu potrzebuj pewnych korekt podczas warunku i sprawdź roczne wyniki.

O wyszukiwaniu bisekcji Spróbuję wyjaśnić tę koncepcję. Zawsze będziesz miał dwie kończyny, minimum i maksimum. I zawsze zacznie zgadywać przez środek kończyn.

Po pierwszym odgadnięciu będziesz musiał dostosować ustawienia kończyn z powodu wyników rocznych. Jeśli po upływie roku, płacąc minimum za drinki, dziewczyny, książki programowe i inne rzeczy, z których nie zapłaciłeś całego salda, masz pewność, że musisz zwiększyć minimum. W przeciwnym razie Jeśli, na przykład, zapłaciłeś całkowite saldo w 10 miesiącu, musisz pić więcej i poznawać nowe dziewczyny w przyszłym roku !!! żartuję ... musisz zmniejszyć minimum. Jest to check trzeba zrobić po zakończonych rok twardych płatności


W ćwiczeniu mamy:

  • bilans i annualInterestRate = dane (nie musimy dbać)
  • minimalna (dolna granica) = Zmiana/12
  • maksymalna (górna granica) = (Stan x (1 + miesięczny oprocentowanie) ** 12)/12,0

Pierwsze przypuszczenie będzie (minimum + maksimum)/2 Zadzwoniłem guessMinimum tak:

guessMinimum = (minimum + maximum)/2 

Więc zaczniesz używać pierwsze przypuszczenie (guessMinimum). Po roku sprawdzisz pozostałość. Jeśli pozostała część jest ujemna, oznacza to, że zapłaciłeś za dużo. musisz zmniejszyć miesięczną opłatę. Poza tym, jeśli po jednym miesiącu pozostała część jest dodatnia (na przykład więcej niż Twoja dokładność (np. 0.10)) musisz zmniejszyć miesięczną opłatę, ok ?!

próby opracowania myślenie .....

+------------------------------------------------+ 
| /\     /\     /\ | 
| \/------------------\/-------------------\/ | 
|MINIMUM    guess    MAXIMUM| 
|      Minimum     | 
+------------------------------------------------+ 

Jeśli po upływie jednego roku, "pozostanie" jest ujemne (na przykład). Oznacza, że ​​"guessMinimum" jest dużo !!! Będziesz potrzebował ... nie ciebie, PROGRAMU !! Program musi go skorygować, obniżyć minimum, aby ......

+---------------------------------------------------+ 
|      Got negative 'remain'  | 
|     ++        | 
| /\    || /\     /\ | 
| \/-------------||---\/-------------------\/ | 
| MINIMUM   || guess    MAXIMUM | 
|     ++ Minimum-,     | 
|        ',     | 
|         `.    | 
|         `.,    | 
|          ',   | 
|          ',   | 
|           `.  | 
|           `  | 
| /\     /\     /\ | 
| \/------------------\/-------------------\/ | 
| MINIMUM    guess    MAXIMUM | 
+---------------------------------------------------+ 

Przykro mi. Próbowałem wstawić obrazek, ale jako nowy członek. Nie mogłem. potrzebuję co najmniej 10 reputacji .... pomóżcie mi !!!! za dużo pracy, aby używać znaków !!!!

a kod trzeba zrobić to ciężka praca, aby ustawić minimalną dopóki pozostają "jest do zaakceptowania (w ciągu swojej precyzji, lub epsilon lub listownie lub zmienna lub .. porządku. :)

Po zrozumieniu koncepcja i rysunki. sprawdźmy CODE.

balance = 999999; 
annualInterestRate = 0.18 

monthlyInterestRate = annualInterestRate/12 

minimum = balance/12 
maximum = (balance * (1 + monthlyInterestRate)**12)/12.0 

guessMinimum = (minimum + maximum)/2 

remain = balance #if you payed nothin, the remain is the balance!!!! 

precision = 0.10 #you choose.... 

while (remain >= precision): 

    guessMinimum = (minimum + maximum)/2 


    for i in range (1,13): 

     newBalance = remain - guessMinimum 
     monthInterest = annualInterestRate/12*newBalance 
     remain = newBalance+monthInterest 

    # after one month, the CODE need to check about the remain 

    if (remain < 0): #paying too much.... need to decrease the value 

     maximum = guessMinimum  #remember my beautiful draw above!! 
     remain = balance # reset the remain to start again!! 

    elif (remain > precision): #paying less .... need to increase the value 
     minimum = guessMinimum 
     remain = balance # reset the remain to start again!! 

print "Lowest Payment: %.2f" %(guessMinimum) 

To wszystko.

1

Oto, co wymyśliłem. Zwykle będę pisać funkcje dla tego typu rzeczy, aby można je było ponownie wykorzystać, nawet gdy nie muszę, ponieważ mam w zwyczaju to robić i daje mi dodatkową praktykę z nimi.

balance = 320000 
annualInterestRate=0.2 
monthlyIntRate= annualInterestRate/12.0 
getpayment=True 
ranonce=False 
MoMin = balance/12 
MoMax = (balance*(1+monthlyIntRate)**12)/12.0 
MoPayment = (MoMin+MoMax)/2 
NewBal=0 

#Create a function to run 12 months of payments, and then create a loop to re-run the function if the Ending Balance is not close enough to 0. 
def CCPayment(balance, monthlyIntRate, MoPay): 
    global NewBal  
    Month = 1 #Month begins at 1 

    while Month <= 12: 
      balance = (balance - MoPay) 
      balance = balance + (monthlyIntRate * balance) 
      NewBal=balance #sets the var NewBal to be used globally 
      Month += 1 
    if (balance < .02) and (balance > -0.02) : #cannot evaluate to '0' as you are evaluating a float and it will 'inf loop'. Must evaluate it to a number 'close enough' 
     return MoPayment 
    else: 
     return False 

while getpayment==True: 
    if CCPayment(balance, monthlyIntRate, MoPayment): 
     getpayment=False 
     print "Lowest Payment: ", round(CCPayment(balance, monthlyIntRate, MoPayment),2) 
    else: 
     if NewBal < 0.01: #paid too much! Lower the max payment and rerun function 
      if ranonce == True: #Bool check to avoid resetting the Min/Max values before running it once 
       MoMax=MoPayment #sets the Max payment to the current monthly payment 
       MoPayment=(MoMin+MoMax)/2 #sets the Monthly payment to average the Min/Max payments 
      ranonce = True 
      CCPayment(balance, monthlyIntRate, MoPayment) 

     elif NewBal > 0.01: #didn't pay enough! Raise min payment and rerun function 
      if ranonce == True: #Bool check to avoid resetting the Min/Max values before running it once 
        MoMin=MoPayment #sets the Min payment to the current monthly payment 
        MoPayment=(MoMin+MoMax)/2 #sets the Monthly payment to average the Min/Max payments 
      ranonce = True 
      CCPayment(balance, monthlyIntRate, MoPayment) 
0
monthlyInterestRate = annualInterestRate/12 
monthlyPaymentLowerBound = balance/12 
monthlyPaymentUpperBound = (balance * (1 + monthlyInterestRate)**12)/12 
epsilon = 0.01 
while True: 
    unpaidBalance = balance 
    minimumFixedMonthlyPayment = (monthlyPaymentLowerBound + monthlyPaymentUpperBound)/2 

    for i in range(12): 
     if i == 0: 
      unpaidBalance = balance - minimumFixedMonthlyPayment 
     else: 
      updatedBalance = unpaidBalance + (monthlyInterestRate * unpaidBalance) 
      unpaidBalance = updatedBalance - minimumFixedMonthlyPayment 

    if unpaidBalance > 0 and abs(unpaidBalance) > epsilon: 
     monthlyPaymentLowerBound = minimumFixedMonthlyPayment 
     minimumFixedMonthlyPayment = (minimumFixedMonthlyPayment + monthlyPaymentUpperBound)/2 
     continue 
    elif unpaidBalance < 0 and abs(unpaidBalance) > epsilon: 
     monthlyPaymentUpperBound = minimumFixedMonthlyPayment 
     minimumFixedMonthlyPayment = (monthlyPaymentLowerBound + minimumFixedMonthlyPayment)/2 
    else: 
     break 
print(round(minimumFixedMonthlyPayment, 2)) 
0

Python 3 odpowiedź:

balance = 999999 
annualInterestRate = .18 

monthlyInterestRate = annualInterestRate/12.0 
lowBound = balance/12 
hiBound = (balance*(1+monthlyInterestRate)**12)/12.0 
epsilon = 0.01 

newBalance = balance 
while abs(newBalance) > epsilon: 
    minPay = (lowBound + hiBound)/2 
    newBalance = balance 
    for month in range(12): 
     monthlyUnpaid = newBalance - minPay 
     newBalance = monthlyUnpaid + (monthlyInterestRate * monthlyUnpaid) 
    if newBalance > epsilon: 
     lowBound = minPay 
    elif newBalance < epsilon: 
     hiBound = minPay 
print ("Lowest Payment: ", round(minPay, 2)) 
Powiązane problemy