【问题标题】:PYTHON - Bisection search MIT Intro to programming in Python PSET1 part 3PYTHON - Bisection search MIT Python PSET1 编程简介第 3 部分
【发布时间】:2017-07-23 13:18:14
【问题描述】:

我正在努力寻找最佳的储蓄率,以在 36 个月内支付 100 万美元的房屋首付。储蓄需要在所需首付的 100 美元以内。首付为总成本的25%。我必须搜索 0 到 10000 之间的整数(使用整数除法),然后将其转换为小数百分比(使用浮点除法),以便在 36 个月后计算 current_savings 时使用。

这是我的代码不起作用(我真的是编程新手)

annual_salary = 150000
total_cost = 1000000
low=0
high=10000
portion_saved=(low+high)/20000.0
epsilon=100
current_savings = 0
portion_down_payment=0.25*total_cost
steps = 0
rate = 0.04
number_of_months = 0
semi_annual_raise = 0.07

while current_savings-portion_down_payment>=epsilon and number_of_months<=36:
current_savings += annual_salary * portion_saved / 12
current_savings += current_savings * rate / 12
number_of_months += 1
if number_of_months % 6 == 0:
annual_salary += annual_salary * semi_annual_raise

if current_savings<portion_down_payment:
    low=portion_saved
else:
    high=portion_saved
portion_saved=(low+high)/20000.0
steps+=1

print("Best savings rate: ", portion_saved)
print("Steps in bisection search", steps)

非常感谢任何帮助!!!

【问题讨论】:

  • 请用minimal reproducible example扩展“不工作”
  • 如果您将代码分解为函数,这可能会更容易。有一个功能,给定储蓄率,在 36 个月后返回余额。有一个函数(给定两个端点、一个目标值和一个函数)进行二等分搜索(或者,考虑到输入函数是平滑的而不是单调的,或者 Newton-Raphson 求解器会更有效)。

标签: python bisection


【解决方案1】:

月收入不随储蓄率变化,所以只计算一次是有意义的:

# 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% 的收入。

如果每月的储蓄可以赚取利息,那么问题就更有趣了(绝对是双关语)。

def savings_balance(monthly_incomes, monthly_interest_rate, savings_rate):
    total = 0.
    for amt in monthly_incomes:
        # At the end of each month,
        total *= 1. + monthly_interest_rate  # we earn interest on what was already saved
        total += amt * savings_rate          # and add a fixed fraction of our monthly income
    return total

我们根据上面的计算来测试一下,

savings_balance(monthly_incomes, 0.0, 0.4659859)   # 249999.9467

所以看起来就像我们预期的那样。

您可以将此函数视为迭代评估 36 次多项式。给定已知的monthly_incomesinterest_rate,我们希望找到savings_rate 以产生所需的total,即找到polynomial - target == 0 的唯一真正正根。如果interest_rate &gt; 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

现在我们像这样运行它

# 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

节省了 45.4%。

【讨论】:

    猜你喜欢
    • 2022-07-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-14
    • 1970-01-01
    • 2017-01-25
    • 1970-01-01
    相关资源
    最近更新 更多