Here's my solution:
irr.rb:
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()
algebra.rb:
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
Comments welcomed. Thanks,
···
On Feb 8, 9:01 am, Ruby Quiz <ja...@grayproductions.net> wrote:
The three rules of Ruby Quiz:
1. Please do not post any solutions or spoiler discussion for this quiz until
48 hours have passed from the time on this message.
2. Support Ruby Quiz by submitting ideas as often as you can:
http://www.rubyquiz.com/
3. Enjoy!
Suggestion: A [QUIZ] in the subject of emails about the problem helps everyone
on Ruby Talk follow the discussion. Please reply to the original quiz message,
if you can.
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- =-=-=
by Harrison Reiser
Internal Rate of Return (IRR -http://en.wikipedia.org/wiki/Internal_rate_of_return\) is a common financial
metric, used by investment firms to predict the profitability of a company or
project. Finding the IRR of a company amounts to solving for it in the equation
for Net Present Value (NPV -http://en.wikipedia.org/wiki/Net_present_value\),
another valuable decision-making metric:
N C_t
NPV = Σ ------------
t=0 (1 + IRR)**t
This week's quiz is to calculate the IRR for any given variable-length list of
numbers, which represent yearly cash flows, the C_t's in the formula above: C_0,
C_1, etc. (C_0 is typically a negative value, corresponding to the initial
investment into the project.) From the example in the Wikipedia article
(http://en.wikipedia.org/wiki/Internal_rate_of_return\), for instance, you should
be able to produce a rate of 17.09% (to four decimal places, let's say) from
this or a similar command:
irr([-100,+30,+35,+40,+45])
=> 0.1709...
Keep in mind that an IRR greater than 100% is possible. Extra credit if you can
also correctly handle input that produces negative rates, disregarding the fact
that they make no sense.