Calculating IRR
So I decided to give the latest Ruby Quiz a shot. I created an `Algebra` module to deal with finding the root of a function -- using Newton's method.
and here is the more specific code to calculate the IRR:
module Algebra
class MaximumIterationsReached < Exception
end
class NewtonsMethod
def self.calculate(function, x)
x - function.evaluated_at(x) / function.derivative_at(x)
end
end
class NewtonsDifferenceQuotient
def self.calculate(function, x, delta=0.1)
(function.evaluated_at(x + delta) - function.evaluated_at(x) ).to_f / delta
end
end
class Function
attr_accessor :differentiation_method, :root_method, :maximum_iterations, :tolerance
def initialize(differentiation_method=NewtonsDifferenceQuotient, root_method=NewtonsMethod, &block)
@definition = block
@differentiation_method, @root_method = differentiation_method, root_method
@maximum_iterations = 1000
@tolerance = 0.0001
end
def evaluated_at(x)
@definition.call(x)
end
def derivative_at(x)
differentiation_method.calculate(self, x)
end
def zero(initial_value=0)
recursive_zero(initial_value, 1)
end
private
def recursive_zero(guess, iteration)
raise MaximumIterationsReached if iteration >= @maximum_iterations
better_guess = @root_method.calculate(self, guess)
if (better_guess - guess).abs <= @tolerance
better_guess
else
recursive_zero(better_guess, iteration + 1)
end
end
end
end require 'algebra'
class IRR
def self.calculate(profits)
begin
function(profits).zero
rescue Algebra::MaximumIterationsReached => mir
nil
end
end
private
def self.function(profits)
Algebra::Function.new do |x|
sumands = Array.new
profits.each_with_index {|profit, index| sumands << profit.to_f / (1 + x) ** index }
sumands.inject(0) {|sum, sumand| sum + sumand }
end
end
end
puts IRR.calculate([-100, 30, 35, 40, 45])
puts IRR.calculate([-1, 1])
puts IRR.calculate([]) 
