PYTHON-对分搜索MIT PYTHON PSET1第3部分编程简介

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*总成

我正在努力寻找最好的储蓄率,以便在36个月内为一栋价值100万美元的房子支付首期款。储蓄需要在所需首付款的100美元以内。首期付款占总成本的25%。我必须搜索一个介于0和10000之间的整数(使用整数除法),然后将其转换为十进制百分比(使用浮点除法),以便在计算当前的成本节约时使用​ 36个月后

这是我的代码,它不工作(我真的是编程新手)

年薪=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