如何使用 Ruby 中的二分法找到小数的最低固定余额

How to find lowest fixed balance in decimals using bisection in Ruby

如何使用 ruby 中的二等分找到 2 dp 的最低固定月付款以支付 12 个月的复利余额?

免责声明:我正确地应用了 upperBound 和 unpaidBalance 公式。

测试用例:

find_fixed_payment(320000, 0.2) should return 29157.09 

但我目前的方法returns中间值29591.87作为固定支付已经绰绰有余了(需要降低到最低)。

我的代码哪里出错了,因为我不确定如何进行二分法(我使用的是二进制搜索)?

def find_fixed_payment(balance,annualInterestRate)
    lowerBound = balance/12
    upperBound = (balance * (1 + annualInterestRate/12)**12) / 12.0
    unpaidBalance = balance

    while true
         middle = (lowerBound + upperBound )/2
         #use middle as the monthly payment at first
        (1..12).each do |i|   
            unpaidBalance = (unpaidBalance - middle) +
              annualInterestRate / 12 * (unpaidBalance - middle)      
        end 

        temp = unpaidBalance.floor
        if temp < 0
            middle -= 0.01
            upperBound = middle
            # should go to for loop to reduce unpaid balance 
            # with new middle but not happening, why?
        else
            middle += 0.01
            lowerBound = middle
        end

        if temp == 0 
            return middle
        end

        if upperBound == lower+1
            return -1
        end

        return middle.round(2)
    end
end

你犯了很多错误,我假设你是从某处的阅读中抄录这个方法的,只是没能理解它描述的过程。

基本上你初始化所有的起始变量,然后你需要创建循环。一旦进入循环,每次计算时,您都需要将余额重置回 320,000,否则它会变成一个移动的目标,我们将永远无法得到您想要的答案。

我在整数 12 上使用了 times 方法来模拟 12 个月的周期,在你的尝试中你使用了一个范围并调用了 each 方法。

现在,我不确定你为什么要那样调整 middle 的值,但这是一个有争议的问题,因为一旦它循环回到你的 while true 循环的开头,它就回到原来的中间值。在我的版本中,我适当地更改了上限或下限。把它想象成猜 1-10 的数字,你足够聪明,知道每次都只选择中间的数字,直到你猜到为止,然后你会从下限 1 和上限 10 开始,然后猜 5。如果我告诉你更高,你现在知道 5 是你的下限,10 仍然是你的上限。

注意:希望这对您有所帮助,欢迎其他用户随时批评和重构我的代码,我最近才开始 ruby。

def find_fixed_payment(balance,annualInterestRate)
    monthlyInterestRate = annualInterestRate / 12 
    lowerBound = balance/12
    upperBound = (balance * (1 + monthlyInterestRate)**12) / 12.0
    unpaidBalance = balance
    accuracy = 0.01

    while unpaidBalance.abs > accuracy 
      balance = unpaidBalance
      middle = (lowerBound + upperBound) / 2
      12.times do
        newUnpaidBalance = unpaidBalance - middle
        monthInterest = monthlyInterestRate * newUnpaidBalance
        unpaidBalance = newUnpaidBalance + monthInterest
      end
      if unpaidBalance < 0
          upperBound = middle
          unpaidBalance = balance
      elsif unpaidBalance > accuracy
          lowerBound = middle
          unpaidBalance = balance
      end
    end
    middle.round(2)
end


find_fixed_payment(320000, 0.2)