Class: Xirr::NewtonMethod

Inherits:
Object
  • Object
show all
Includes:
Base
Defined in:
lib/xirr/newton_method.rb

Overview

Plain Newton-Raphson: step from the guess by -xnpv/xnpv' until the step is smaller than the tolerance. Fast when it converges, but with no bracketing it can walk off to a non-root or below -100%; RtSafe is the safeguarded default that avoids that. Kept for xirr(method: :newton_method).

Instance Attribute Summary

Attributes included from Base

#cf

Instance Method Summary collapse

Methods included from Base

#initialize, #periods_from_start, #xnpv, #xnpv_derivative

Instance Method Details

#xirr(guess, options) ⇒ Float?

Returns the rate rounded to Xirr.config.precision, or nil.

Parameters:

  • guess (Float, nil)

    initial rate

  • options (Hash)

    reads :iteration_limit

Returns:

  • (Float, nil)

    the rate rounded to Xirr.config.precision, or nil



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/xirr/newton_method.rb', line 14

def xirr(guess, options)
  limit = (options && options[:iteration_limit]) || Xirr.config.iteration_limit
  rate = (guess || cf.irr_guess).to_f

  limit.times do
    derivative = xnpv_derivative(rate)
    return nil if derivative.zero?

    step = xnpv(rate).to_f / derivative
    rate -= step
    # Below -100% the discount base (1 + rate) turns negative and the next
    # xnpv raises it to a fractional power, producing a Complex. Bail first.
    return nil if rate.nan? || rate.infinite? || rate <= -1
    break if step.abs < Xirr.config.eps
  end

  rate.nan? ? nil : rate.round(Xirr.config.precision)
rescue FloatDomainError, Math::DomainError, RangeError
  nil
end