class Solver

Constants

INTERVAL
MAX_ITERATIONS
PRECISION

Attributes

goal[R]
iteration_count[RW]
lower_bound[RW]
time_value[R]
upper_bound[RW]
upper_cap_met[RW]

Public Class Methods

new(time_value:, lower_bound: 0.00, upper_bound: nil, guess: 10.00) click to toggle source
# File lib/solver.rb, line 9
def initialize(time_value:, lower_bound: 0.00, upper_bound: nil, guess: 10.00)
  @upper_bound = upper_bound || guess
  @lower_bound = lower_bound
  @time_value = time_value.dup
  @time_value.i = guess
  @goal = time_value.fv
  @upper_cap_met = false
  @iteration_count = 0
end

Public Instance Methods

solve!() click to toggle source
# File lib/solver.rb, line 19
def solve!
  while !within_range? && iteration_count < MAX_ITERATIONS
    result = time_value.calc_fv
    adjust_bounds!(result: result)
    time_value.i = new_guess
    self.iteration_count += 1
  end
  # TODO: This will not handle the case where the 20th iteration
  # finds the solution
  return rounded_rate if iteration_count < MAX_ITERATIONS
rescue FloatDomainError
  return nil
end

Private Instance Methods

adjust_bounds!(result:) click to toggle source
# File lib/solver.rb, line 39
def adjust_bounds!(result:)
  if result > goal
    # interest rate too high
    self.upper_cap_met = true
    self.upper_bound = rate
  elsif result < goal
    # interest rate too low
    self.upper_bound *= 2 unless upper_cap_met
    self.lower_bound = rate
  end
end
new_guess() click to toggle source
# File lib/solver.rb, line 51
def new_guess
  ((upper_bound + lower_bound) / 2).round(PRECISION)
end
rate() click to toggle source
# File lib/solver.rb, line 55
def rate
  time_value.i
end
rounded_rate() click to toggle source
# File lib/solver.rb, line 59
def rounded_rate
  time_value.i.round(2)
end
within_range?() click to toggle source
# File lib/solver.rb, line 35
def within_range?
  (upper_bound - lower_bound).round(PRECISION) <= INTERVAL
end