簡體   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