8

我正在尝试使用以下方法计算偿还贷款的最低每月付款:

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

但是,我似乎陷入了某种无限循环,我的guess变量没有被更新。如何跳出无限循环并guess更新我的变量?

问题出在我的数学上。我的意思是说

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

谢谢大家的帮助!

4

8 回答 8

11

首先,如果您正在做 MITx 练习并完成了之前的测试(只是为了增加 10 猜测),那么您只需一小步即可获得它。只需要对while条件进行一些调整并检查年度结果。

关于二分搜索,我将尝试澄清这个概念。你总是有两个极端,最小的和最大的。并且总是从四肢的中间开始猜测。

在第一次猜测之后,您需要根据年度结果调整四肢。如果一年后为饮料、女孩、节目书和其他东西支付了最低金额,但您没有支付总余额,那么您肯定需要提高最低金额。否则,例如,如果您在第 10 个月支付了全部余额,则您需要多喝水,并在明年结识新的女孩!!!开个玩笑……你需要减少最低限度。这是您在完成一年的硬付款后需要做的检查


在练习中,我们有:

  • 余额和年利率=给定(我们不需要关心)
  • 最小值(下限)= 余额 / 12
  • 最大值(上限)=(余额 x(1 + 月利率)**12)/12.0

第一个猜测是 (minimum + maximum) /2 我叫guessMinimum,所以:

guessMinimum = (minimum + maximum)/2

所以你将开始使用第一个猜测(guessMinimum)。一年后,您将检查剩余部分。如果剩余为负数,则意味着您付出了太多。您需要减少每月付款。另外,如果一个月后剩余为正数(例如,超过您的精度(例如 0.10)),您需要减少每月付款,好吗?!

试图设计思维......

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

如果一年后,“剩余”为负数(例如)。意味着“guessMinimum”太多了!!!你需要......不是你,程序!程序需要调整它,降低最小值所以......

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

对不起大家。我尝试插入图像,但作为新成员。我不能。至少需要10个声望....帮帮我!!!使用角色的工作量太大了!!!!

并且代码需要做这项艰苦的工作来调整最小值,直到“剩余”是可以接受的(在你的精度内,或 epsilon,或任何字母或变量或......好吧。:)

了解概念和图纸后..让我们检查代码。

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)

而已。

于 2015-01-16T17:16:43.080 回答
5

我认为这个解决方案应该有效,

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)
于 2013-12-01T12:09:27.270 回答
3

要找出这样的错误,一个好方法就是添加一些打印,例如,我在您的代码中添加了以下内容:

print(balance, lo, hi, guess)

然后看看会发生什么,你就能弄清楚发生了什么。事实证明:

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

计算一个太低的上限。也许你的意思是:

hi = (balance*(1+monthlyInterestRate*12))/12
于 2013-03-18T19:38:18.010 回答
3

我将您的代码更改为:

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"

一些注意事项:我将“hi”和“lo”更改为“high”和“low”。最好不要截断变量名,因为截断的变量名可读性较差。

我添加了显示各种变量值的调试语句。

这是上面运行的结果:

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

从这里你可以看到你的低价值正在向你的高价值收敛。换句话说,您的初始高值还不够高。一旦它们的值相同,循环将永远不会改变任何东西并将永远持续下去。

我认为这一行:

elif balance < 0 and balance < -epsilon:

应该读:

elif balance < 0 and balance > -epsilon:

因为我认为你想要平衡0-epsilon而不是小于-epsilon

此外,正如@WinstonEwert 指出的那样:

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

应该

hi = (balance*(1+monthlyInterestRate)**12)/12 
于 2013-03-18T19:54:12.410 回答
1

这是我想出的作品。我通常会为这些类型的东西编写函数,以便它可以重复使用,即使我不需要这样做,因为它让我养成了这样做的习惯,并给了我一些额外的练习。

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)
于 2016-01-28T17:41:09.260 回答
0
    balance = balance
annualInterestRate = annualInterestRate
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
于 2019-06-01T14:32:55.040 回答
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))
于 2016-11-13T00:35:08.800 回答
0

Python 3 答案:

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))
于 2017-06-18T14:41:19.903 回答