lib/xirr/bisection.rb in xirr-0.5.2 vs lib/xirr/bisection.rb in xirr-0.5.3

- old
+ new

@@ -6,50 +6,25 @@ # Calculates yearly Internal Rate of Return # @return [BigDecimal] # @param midpoint [Float] # An initial guess rate will override the {Cashflow#irr_guess} - def xirr midpoint + def xirr midpoint, options # Initial values left = [BigDecimal.new(-0.99999999, Xirr::PRECISION), cf.irr_guess].min right = [BigDecimal.new(9.99999999, Xirr::PRECISION), cf.irr_guess + 1].max @original_right = right midpoint ||= cf.irr_guess - runs = 0 - while (right - left).abs > Xirr::EPS && runs < Xirr::ITERATION_LIMIT do - runs += 1 - left, midpoint, right, should_stop = bisection(left, midpoint, right) - break if should_stop - if right_limit_reached?(midpoint) - right = right * 2 - @original_right = @original_right * 2 - end - end + midpoint, runs = loop_rates(left, midpoint, right, options[:iteration_limit]) - # - # # Loops until difference is within error margin - # while (right - left).abs > Xirr::EPS && runs < Xirr::ITERATION_LIMIT do - # - # - # end + get_answer(midpoint, options, runs) - if runs >= Xirr::ITERATION_LIMIT - if cf.raise_exception - raise ArgumentError, "Did not converge after #{runs} tries." - else - return nil - end - end - - # return nil if right_limit_reached?(midpoint) - - return midpoint.round Xirr::PRECISION - end + private # @param midpoint [BigDecimal] # @return [Boolean] # Checks if result is the right limit. @@ -85,9 +60,36 @@ # @param right [Float] # @return [Float] IRR of the Cashflow def format_irr(left, right) irr = (right+left) / 2 end + + def get_answer(midpoint, options, runs) + if runs >= options[:iteration_limit] + if options[:raise_exception] + raise ArgumentError, "Did not converge after #{runs} tries." + else + nil + end + else + midpoint.round Xirr::PRECISION + end + end + + def loop_rates(left, midpoint, right, iteration_limit) + runs = 0 + while (right - left).abs > Xirr::EPS && runs < iteration_limit do + runs += 1 + left, midpoint, right, should_stop = bisection(left, midpoint, right) + break if should_stop + if right_limit_reached?(midpoint) + right = right * 2 + @original_right = @original_right * 2 + end + end + return midpoint, runs + end + end end