PYTHON-对分搜索MIT PYTHON PSET1第3部分编程简介
我正在努力寻找最好的储蓄率,以便在36个月内为一栋价值100万美元的房子支付首期款。储蓄需要在所需首付款的100美元以内。首期付款占总成本的25%。我必须搜索一个介于0和10000之间的整数(使用整数除法),然后将其转换为十进制百分比(使用浮点除法),以便在计算当前的成本节约时使用 36个月后 这是我的代码,它不工作(我真的是编程新手)PYTHON-对分搜索MIT PYTHON PSET1第3部分编程简介,python,bisection,Python,Bisection,我正在努力寻找最好的储蓄率,以便在36个月内为一栋价值100万美元的房子支付首期款。储蓄需要在所需首付款的100美元以内。首期付款占总成本的25%。我必须搜索一个介于0和10000之间的整数(使用整数除法),然后将其转换为十进制百分比(使用浮点除法),以便在计算当前的成本节约时使用 36个月后 这是我的代码,它不工作(我真的是编程新手) 年薪=150000 总成本=1000000 低=0 高=10000 保存的部分=(低+高)/20000.0 ε=100 当前储蓄=0 部分首付=0.25*总成
年薪=150000
总成本=1000000
低=0
高=10000
保存的部分=(低+高)/20000.0
ε=100
当前储蓄=0
部分首付=0.25*总成本
步数=0
比率=0.04
月数=0
半年度加薪=0.07
虽然当前储蓄部分首付>=ε和月数但月收入不随储蓄率变化,因此只计算一次是有意义的:
# calculate income per month over 36 months
base_monthly_salary = 150000 // 12
semiannual_raise = 0.07
monthly_incomes = [base_monthly_salary * (1. + semiannual_raise) ** (month // 6) for month in range(36)]
如果每月储蓄不产生利息,问题就很简单:
target_amount = 1000000. * 0.25
savings_rate = target_amount / sum(monthly_incomes) # 0.4659859
所以你必须把收入的46.6%存起来
如果每个月的储蓄都能获得利息,那么问题就更有趣了(这绝对是个糟糕的双关语)
让我们根据上面的计算进行测试
savings_balance(monthly_incomes, 0.0, 0.4659859) # 249999.9467
所以这看起来像我们所期望的
您可以将此函数视为迭代计算36次多项式。给定已知的月收入
和利率
,我们希望找到储蓄率
,以产生所需的总额
,即找到多项式-target==0的唯一真正正根。如果利率>0,则没有解析解。
,因此我们将尝试数值解
target_amount = 1000000. * 0.25
# Make up a number: annual savings interest = 1.9%
monthly_interest_rate = 0.019 / 12.
# Our solver expects a single-argument function to solve, so let's make it one:
def fn(x):
return savings_balance(monthly_incomes, monthly_interest_rate, x)
def bisection_search(fn, lo, hi, target, tolerance=0.1):
# This function assumes that fn is monotonically increasing!
# check the end-points - is a solution possible?
fn_lo = fn(lo)
assert not target < -tolerance + fn_lo, "target is unattainably low"
if abs(target - fn_lo) <= tolerance:
return lo
fn_hi = fn(hi)
assert not fn_hi + tolerance < target, "target is unattainably high"
if abs(target - fn_hi) <= tolerance:
return hi
# a solution is possible but not yet found -
# repeat until we find it
while True:
# test the middle of the target range
mid = (lo + hi) / 2
fn_mid = fn(mid)
# is this an acceptable solution?
if abs(target - fn_mid) <= tolerance:
return mid
else:
# do we need to look in the lower or upper half?
if target < fn_mid:
# look lower - bring the top down
hi = mid
else:
# look higher - bring the bottom up
lo = mid
这使节省率达到45.4%。请详细说明“不工作”与a。如果将代码分解为函数,这可能会更容易。有一个函数,给定储蓄率,在36个月后返回余额。有一个函数(给定两个端点、一个目标值和一个函数)进行对分搜索(或者,如果输入函数是平滑的,而不仅仅是单调的,牛顿-拉斐逊解算器会更有效)。
savings_balance(monthly_incomes, 0.0, 0.4659859) # 249999.9467
target_amount = 1000000. * 0.25
# Make up a number: annual savings interest = 1.9%
monthly_interest_rate = 0.019 / 12.
# Our solver expects a single-argument function to solve, so let's make it one:
def fn(x):
return savings_balance(monthly_incomes, monthly_interest_rate, x)
def bisection_search(fn, lo, hi, target, tolerance=0.1):
# This function assumes that fn is monotonically increasing!
# check the end-points - is a solution possible?
fn_lo = fn(lo)
assert not target < -tolerance + fn_lo, "target is unattainably low"
if abs(target - fn_lo) <= tolerance:
return lo
fn_hi = fn(hi)
assert not fn_hi + tolerance < target, "target is unattainably high"
if abs(target - fn_hi) <= tolerance:
return hi
# a solution is possible but not yet found -
# repeat until we find it
while True:
# test the middle of the target range
mid = (lo + hi) / 2
fn_mid = fn(mid)
# is this an acceptable solution?
if abs(target - fn_mid) <= tolerance:
return mid
else:
# do we need to look in the lower or upper half?
if target < fn_mid:
# look lower - bring the top down
hi = mid
else:
# look higher - bring the bottom up
lo = mid
# From above, we know that
# when interest = 0.0 we need a savings rate of 46.6%
#
# If interest > 0. the savings_rate should be smaller,
# because some of target_amount will be covered by generated interest.
#
# For a small annual_interest_rate over an N year term,
# the effective accrued interest rate will be close to
# N * annual_interest_rate / 2 -> 1.5 * 1.9% == 2.85%
#
# So we expect the required savings rate to be
# about 46.6% * (1. - 0.0285) == 45.3%
bisection_search(fn, 0.40, 0.47, target_amount) # 0.454047973