From: Jason Dew Date: 2008-02-11T05:51:57+09:00 Subject: Re: Internal Rate of Return (#156) 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 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.