使用二分查找法在Python中计算最低月付款额

8 投票
8 回答
21336 浏览
提问于 2025-04-17 19:32

我正在尝试计算每月最低还款额,以偿还一笔贷款,使用的是以下代码:

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

谢谢大家的帮助!

8 个回答

3

要找出像这样的错误,一个好办法就是加一些打印输出,比如我在你的代码里加了以下内容:

print(balance, lo, hi, guess)

然后看看会发生什么,这样你就能弄清楚到底出了什么问题。结果发现:

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

计算出的上限太低了。也许你想要的是:

hi = (balance*(1+monthlyInterestRate*12))/12
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)
11

首先,如果你在做MITx的练习,并且完成了之前的测试(只需在猜测中加10),那么你离成功又近了一步。只需要对循环条件做一些调整,并检查一下年度结果。

关于二分查找,我来简单解释一下这个概念。你总是会有两个极端,一个是最小值,一个是最大值。每次猜测时,都是从这两个极端的中间开始。

第一次猜测后,你需要根据年度结果来调整这两个极端。如果在一年后,你支付了喝饮料、约女孩、买程序书和其他东西的最低金额,但仍然没有还清总账,那你肯定需要提高最低支付额。反之,如果比如说你在第十个月就还清了总账,那你明年就得多喝点、认识新女孩!开玩笑的……你需要降低最低支付额。这就是在完成一年的支付后需要检查的内容。


在这个练习中,我们有:

  • 余额和年利率 = 给定的(我们不需要关心)
  • 最低支付额(下限) = 余额 / 12
  • 最高支付额(上限) = (余额 x (1 + 月利率)**12) / 12.0

第一次猜测将是(最低 + 最高)/ 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)

就是这样。

撰写回答