diff --git a/CHANGE_LOG.md b/CHANGE_LOG.md index 1131829..f85d104 100644 --- a/CHANGE_LOG.md +++ b/CHANGE_LOG.md @@ -1,8 +1,11 @@ +## Version 0.2.6 + +* New Bisection method to avoid not converging to negative IRRs if not enough precision + ## Version 0.2.5 * Default XIRR does not raise an Exception if cashflow is invalid - ## Version 0.2.4 * Cashflow Invalid Messages are now public. diff --git a/lib/xirr/bisection.rb b/lib/xirr/bisection.rb index 2e57d4e..c336a86 100644 --- a/lib/xirr/bisection.rb +++ b/lib/xirr/bisection.rb @@ -20,8 +20,7 @@ def xirr(midpoint = nil) while ((right - left).abs > Xirr::EPS && runs < Xirr.config.iteration_limit.to_i) do runs += 1 - npv_positive?(midpoint) == npv_positive?(left) ? left = midpoint : right = midpoint - midpoint = format_irr(left, right) + left, midpoint, right = bisection(left, midpoint, right) end @@ -35,6 +34,24 @@ def xirr(midpoint = nil) private + # @param left [BigDecimal] + # @param midpoint [BigDecimal] + # @param right [BigDecimal] + # @return [Array] + # Calculates the Bisections + def bisection(left, midpoint, right) + _left, _mid = npv_positive?(left), npv_positive?(midpoint) + if _left && _mid + return left, left, left if npv_positive?(right) # Not Enough Precision in the left to find the IRR + else + if _left == _mid + return midpoint, format_irr(midpoint, right), right # Result is to the Right + else + return left, format_irr(left, midpoint), midpoint # Result is to the Left + end + end + end + # @param midpoint [Float] # @return [Bolean] # Returns true if result is to the right ot the range diff --git a/lib/xirr/version.rb b/lib/xirr/version.rb index 98a0b8b..aed4f66 100644 --- a/lib/xirr/version.rb +++ b/lib/xirr/version.rb @@ -1,4 +1,4 @@ module Xirr # Version of the Gem - VERSION = "0.2.5" + VERSION = "0.2.6" end