繁体   English   中英

均分搜索以选择最佳储蓄率

[英]Bisect Search to choose best savings rate

嗨,我希望获得有关此问题的帮助,这是MIT OCW计算机科学和Python课程中的问题之一。 我知道人们也问过类似的问题,但我发现有用的帖子(例如, Bisection搜索代码)不起作用,但我仍然被卡住了!

我已经为这个问题苦苦挣扎了许多天,并试图以不同的方式来解决这个问题,但是在所有方面都以失败告终。 如果可能的话,有人能暗示我要去哪里,而不是告诉我答案。 我想通过一点帮助自己解决这个问题。

作为参考,问题是C部分,在这里: https : //ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-0001-introduction-to-computer-science-and-programming-in -python下落-2016 /任务/ MIT6_0001F16_ps1.pdf

在努力的过程中,我将这项任务分解为一个总体目标,然后分解为解决问题的步骤。

目标:尝试找到最佳的储蓄率,以在36个月内实现首付100万美元房屋的首付。##解决问题的步骤:
1)猜测储蓄率,即0和1000的平均值
2)计算36个月后的增长情况
3a)如果在36个月内达到的金额超过100万美元的25%,那么较低的储蓄率应该是新的猜测
... max =猜测(旧的猜测)和min = 0并更新猜测(高和低的平均值)
...使用新的猜测运行步骤2中的计算
3b)如果金额在36个月内未达到100万美元的25%,则应以更高的储蓄率作为新的猜测
... min = guess(旧的猜测)并更新猜测(高和低的平均值)...使用新的猜测运行步骤2中的计算
3c)如果金额在第36个月的截止日期内达到100万美元的25%,则退出并记录储蓄率作为最佳猜测。
为简单起见:假设没有利息,并且假设工资保持不变

所以这是我目前正在努力解决此问题的代码。 (这导致“猜测”变量趋向于0,然后无限循环)

total_cost=1000000 #cost of house
portion_down_payment=0.25 #fraction of cost needed for downpayment on house
downpayment=total_cost*portion_down_payment

starting_annual_salary=float(input("Enter the starting salary: "))
low=0
high=1000
bisect_steps=0
month=1 #set as 1 because the first calculation will occur in month 1 
guess=(low+high)//2
current_savings=0

def calSavings(current_savings,monthly_salary,guess,month):
    while month<37:
        monthly_savings=monthly_salary*(guess/1000)
        current_savings+=monthly_savings
        month+=1
    return(current_savings) 

current_savings=calSavings(current_savings,monthly_salary,guess,1)
while True:
    current_savings=calSavings(current_savings,monthly_salary,guess,1)
    if current_savings>downpayment and month<=35: #if amount reached goes over 25% of $1m within 36 months
        #a lower savings rate should be the new guess
        high=guess #max=guess (old guess) and min=0 and update the guess
        bisect_steps+=1
        guess=(low+high)//2
        print("The guess was too high, so the new lower guess is",guess," This is bisect step",bisect_steps)
        continue #send new guess up to beginning of while loop to calculate 
    elif current_savings<downpayment and month>=36: #if amount does not reach 25% of $1m within 36 months
        low=guess
        bisect_steps=+1
        guess=(low+high)//2
        print("The guess was too low, so the new higher guess is",guess," This is bisect step",bisect_steps)
        continue #send new guess up to beginning of while loop to calculate 
    elif current_savings>=downpayment and month==36: #if amount reaches 25% of $1m in the 36th months then quit
        # record the savings rate as the best guess
        print("The best savings rate is ",guess/100,"%, the amount saved was ",current_savings," in ",month," months")
        break #break out of while loop

我知道其他人也曾问过类似的问题(我已经看过这些答案,但仍然没有解决我的问题),但我想获得的更多帮助是如何解决此问题的帮助。

更新

循环没有停止的原因是因为您没有给它足够的时间。 您忘记的是您正在处理decimal类型。 ==decimal值一起使用总是很危险的。 decimal类型准确(默认情况下)为28个位,这意味着您正尝试找到一个非常好的近似值,因为只有当它正确为28个小数时, (current_savings>downpayment or current_savings<downpayment)评估结果才为False调用您的退出条件。

基本上,导致您出现问题的问题是,即使您最终获得的估算值为$ 1,000,000.0000000001,python表示这也不等于$ 1,000,000.0000000000,因此它一直持续到得到下一个0,然后才添加另一个零,依此类推。 。 这将持续非常长的时间,在极少数情况下,由于并非所有十进制数字都可以存储为二进制数(1,000,000不在这种情况下),因此可能永远不会停止。

那么,我们该如何解决呢? 有两种选择。 最简单的方法是忽略美分,只将比较值转换为int ,这将确保接受少于一美元的任何值。 其他选项是创建一系列可接受的答案。 举例来说,在这36个月中,我想节省100万美元,但这不太可能实现。 因此,我将以$ 1,000,000.00-$ 1,000,010.00范围内的任何金额结算(例如)。 这样,我们确保任何过高的猜测都将被拒绝,并且仅接受非常有限的猜测。

无论走哪条路线,通常最好将无限循环的退出条件放在顶部,这样可以保证始终对它进行评估。

我的建议是编写一个这样的函数,并使用该函数使条件退出循环(将其放置在顶部):

def are_decimals_equal(a, b):
    accuracy = 0.0001
    return abs(a-b) < accuracy

这将认为0.00009(以及所有小于该数值的小数)等于0.0000。

原版的

首先,请注意,您所做的不是二分法,而是二元搜索。

现在解决问题,您永远不会在主循环中更改month的值。 这意味着,只要current_savings>downpayment评估结果为False,您的程序便会进入无限循环,因为在month>=36的情况下,该程序在任何条件下都可以评估为True时始终为False。

据我所知,if / elif语句中条件的第二部分是不必要的,您的calSavings总是可以计算出36个月的节省额,永远不会多,也永远不会少。 因此,如果您从if / elif语句中删除该条件,则您的程序最终将停止,并且此时应确定正确的答案。

最后,您看到0作为输出的原因是最后的除法。 如果您执行print(typeof(guess))您会看到它是一个整数,100也是一个整数,因此该除法将导致某些值(如0.3123将被截断为0 将您的输出更改为float(guess/100) ,这将消失。

我希望我可以在这里回答自己的问题,尽管这不是一个完美的答案。

代码产生的结果似乎是合理的。

total_cost=1000000 #cost of house

portion_down_payment=0.25 #fraction of cost needed for downpayment on house
downpayment=total_cost*portion_down_payment

starting_annual_salary=float(input("Enter the starting salary: "))
monthly_salary=starting_annual_salary/12
low=0
high=1000
binary=0
month=1 #set as 1 because the first calculation will occur in month 1
guess=(low+high)//2
current_savings=0
tolerance=500

def calSavings(current_savings,monthly_salary,guess,month):
    while month<37:
        monthly_savings=int(monthly_salary*(guess/1000))
        current_savings+=monthly_savings
        month+=1
    return(current_savings)

current_savings=calSavings(current_savings,monthly_salary,guess,1)

while True:
    if abs(current_savings-downpayment)<=tolerance: #if the difference between the current savings and downpayment is less than $500
        # record the savings rate as the best guess
        print("The best savings rate is ",guess/10,"%, the amount saved was $",current_savings," in 36 months")
        break #break out of while loop
    elif (current_savings-downpayment)>tolerance: #if amount reached goes over 25% of $1m within 36 months
        #a lower savings rate should be the new guess
        high=guess #high=guess (old guess) and low=low (stays same) and update the guess
        binary=binary+1
        guess=(low+high)//2
        print("The guess was too high, so the new lower savings rate is",guess/10,"%. This is binary-search step",binary)
        current_savings=calSavings(0,monthly_salary,guess,1)
        continue #send new guess up to beginning of while loop to check if conditionals
    elif (downpayment-current_savings)>tolerance: #if amount does not come to within tolerance amount of 25% of $1m within 36 months
        low=guess #to make the guess higher, make low=guess (old guess) and high stay the same
        binary=binary+1
        guess=(low+high)//2
        print("guess is ",guess)
        if guess>=990: #check if the savings rate guess is getting too high
            print("Your wages are too low. You can't save up enough")
            break #exit the while loop because conditions will never be met
        print("The guess was too low, so the new higher savings rate is",guess/10,"%. This is binary-search step",binary)
        current_savings=calSavings(0,monthly_salary,guess,1)
        continue #send new guess up to beginning of while loop to check over the conditionals

可接受的答案的公差在500美元以内,但是如果我将其降低到50美元,我将再次陷入看似无限的循环,猜测和低端的结果相同。 我很高兴自己已经取得了一些明显的进步,但是对不能再忍受它无法降低容忍度感到困惑。

顺便说一句,我不想​​我似乎忽略了尼克关于将变量转换为浮点数的评论,但是我解释了为什么我在评论中使用整数-看起来正确吗?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM