[英]Computing the lowest monthly payment using bisection search in 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
但是,我似乎陷入了某种无限循环,其中我的guess
变量没有更新。 如何突破无限循环并更新我的guess
变量?
问题出在我的数学上。 我的意思是
hi = (balance*(1+monthlyInterestRate)**12)/12
谢谢大家的帮助!
首先,如果您正在做MITx练习并完成了之前的测试(猜测中只是增加10),那么您迈出了一步。 只需要对条件进行一些调整并检查年度结果即可。
关于二等分搜索,我将尝试阐明概念。 您将始终有两个末端,最小和最大。 并且总是会在四肢中间开始猜测。
第一次猜测后,由于年度结果,您需要调整四肢。 如果在一年后支付了最低的酒水,女孩,课程书籍和其他费用,而您没有支付总余额,那么您肯定需要提高最低费用。 否则,例如,如果您在第10个月支付了总余额,则您需要多喝酒,并在明年认识新女孩!!! 开个玩笑...您需要降低下限。 这是您在完成一年的硬付款后需要做的检查
在练习中,我们有:
第一个猜测将是(最小+最大值)/ 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个声望....帮助我!!!! 太多的工作无法使用角色!!!
并且CODE需要付出艰辛的工作来调整最小值,直到可以接受“剩余”值为止(在您的精度范围内,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)
而已。
我认为此解决方案应该有效,
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)
为了找出此类错误,一个好方法就是添加一些打印内容,例如,我在代码中添加了以下内容:
print(balance, lo, hi, guess)
然后查看发生了什么,您可以弄清楚发生了什么。 事实证明:
hi = (balance*(1+monthlyInterestRate**12))/12
计算的上限太低。 也许您的意思是:
hi = (balance*(1+monthlyInterestRate*12))/12
我将您的代码更改为此:
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
这是我想出的方法。 我通常会为这类事情编写函数,以便即使在不需要时也可以重复使用它,因为它使我养成了这样做的习惯,并为我提供了一些额外的练习。
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)
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))
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))
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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.