[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Re: [QUIZ] Internal Rate of Return (#156

James Koppel

2/10/2008 4:29:00 PM

Here's my solution. I used Newton's method to quickly find the zero of the =
NPV function.=0A=0AUnfortunately, my calculus book failed to mention that N=
ewton's method will fail to converge when the function enters a horizontal =
asymptote if it's moving toward y=3D0 as it does so, which happens in this =
function at deeply negative values of IRR. Thus, my solution can be a bit u=
nreliable, especially for negative values of IRR.=0A=0AAnyway, here's the c=
ode:=0A=0ADX =3D 1e-4=0AEPSILON =3D 1e-7=0A=0Adef nderiv(f)=0A lambda {|x|=
(f[x+DX]-f[x-DX])/(2*DX)}=0Aend=0A=0AMAX_ITERATIONS =3D 500=0Adef find_zer=
o(f, start)=0A iterations =3D 0=0A f_prime =3D nderiv(f)=0A x =3D start=
=0A until f[x].abs < EPSILON or (iterations+=3D1) > MAX_ITERATIONS=0A x=
=3D x - f[x]/f_prime[x]=0A end=0A if iterations > MAX_ITERATIONS=0A n=
il=0A else=0A x=0A end=0Aend=0A=0Adef irr(cash_flows)=0A net_value =
=3D lambda do |irr|=0A (0...cash_flows.length).to_a.inject(0) do |s,t|=
=0A s+cash_flows[t]/((1+irr)**t)=0A end=0A end=0A =0A find_zero(=
net_value,0.1) or find_zero(net_value,-0.1)=0Aend=0A=0A----- Original Messa=
ge ----=0AFrom: Ruby Quiz <james@grayproductions.net>=0ATo: ruby-talk ML <r=
uby-talk@ruby-lang.org>=0ASent: Friday, February 8, 2008 8:01:13 AM=0ASubje=
ct: [QUIZ] Internal Rate of Return (#156)=0A=0A=0AThe =0Athree =0Arules =0A=
of =0ARuby =0AQuiz:=0A=0A1. =0APlease =0Ado =0Anot =0Apost =0Aany =0Asolut=
ions =0Aor =0Aspoiler =0Adiscussion =0Afor =0Athis =0Aquiz =0Auntil=0A48 =
=0Ahours =0Ahave =0Apassed =0Afrom =0Athe =0Atime =0Aon =0Athis =0Amessage.=
=0A=0A2. =0ASupport =0ARuby =0AQuiz =0Aby =0Asubmitting =0Aideas =0Aas =0A=
often =0Aas =0Ayou =0Acan:=0A=0Ahttp://www.rubyquiz.c.... =0AEnjoy!=
=0A=0ASuggestion: =0AA =0A[QUIZ] =0Ain =0Athe =0Asubject =0Aof =0Aemails =
=0Aabout =0Athe =0Aproblem =0Ahelps =0Aeveryone=0Aon =0ARuby =0ATalk =0Afol=
low =0Athe =0Adiscussion. =0APlease =0Areply =0Ato =0Athe =0Aoriginal =0Aq=
uiz =0Amessage,=0Aif =0Ayou =0Acan.=0A=0A-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=
=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D=
-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D=0A=0Aby =0AHarrison =
=0AReiser=0A=0AInternal =0ARate =0Aof =0AReturn =0A(IRR =0A=E2=80=93=0Ahttp=
://en.wikipedia.org/wiki/Internal_rate_of_return) =0Ais =0Aa =0Acommon =0Af=
inancial=0Ametric, =0Aused =0Aby =0Ainvestment =0Afirms =0Ato =0Apredict =
=0Athe =0Aprofitability =0Aof =0Aa =0Acompany =0Aor=0Aproject. =0AFinding =
=0Athe =0AIRR =0Aof =0Aa =0Acompany =0Aamounts =0Ato =0Asolving =0Afor =0Ai=
t =0Ain =0Athe =0Aequation=0Afor =0ANet =0APresent =0AValue =0A(NPV =0A=E2=
=80=93 =0Ahttp://en.wikipedia.org/wiki/Net_pre...),=0Aanother =0Aval=
uable =0Adecision-making =0Ametric:=0A=0A =0A =0A =0A =0A =0AN =0A =
=0A =0AC_t=0A =0ANPV =0A=3D =0A=CE=A3 =0A------------=0A =0A =0A =
=0A =0At=3D0 =0A(1 =0A+ =0AIRR)**t=0A=0AThis =0Aweek's =0Aquiz =0Ais =0At=
o =0Acalculate =0Athe =0AIRR =0Afor =0Aany =0Agiven =0Avariable-length =0Al=
ist =0Aof=0Anumbers, =0Awhich =0Arepresent =0Ayearly =0Acash =0Aflows, =0At=
he =0AC_t's =0Ain =0Athe =0Aformula =0Aabove: =0AC_0,=0AC_1, =0Aetc. =0A(C_=
0 =0Ais =0Atypically =0Aa =0Anegative =0Avalue, =0Acorresponding =0Ato =0At=
he =0Ainitial=0Ainvestment =0Ainto =0Athe =0Aproject.) =0AFrom =0Athe =0Aex=
ample =0Ain =0Athe =0AWikipedia =0Aarticle=0A(http://en.wikipedia....
Internal_rate_of_return), =0Afor =0Ainstance, =0Ayou =0Ashould=0Abe =0Aable=
=0Ato =0Aproduce =0Aa =0Arate =0Aof =0A17.09% =0A(to =0Afour =0Adecimal =
=0Aplaces, =0Alet's =0Asay) =0Afrom=0Athis =0Aor =0Aa =0Asimilar =0Acommand=
:=0A=0A =0Airr([-100,+30,+35,+40,+45])=0A =0A=3D> =0A0.1709...=0A=0AK=
eep =0Ain =0Amind =0Athat =0Aan =0AIRR =0Agreater =0Athan =0A100% =0Ais =0A=
possible. =0AExtra =0Acredit =0Aif =0Ayou =0Acan=0Aalso =0Acorrectly =0Ahan=
dle =0Ainput =0Athat =0Aproduces =0Anegative =0Arates, =0Adisregarding =0At=
he =0Afact=0Athat =0Athey =0Amake =0Ano =0Asense.=0A=0A=0A=0A=0A=0A=0A =
__________________________________________________________________________=
__________=0ABe a better friend, newshound, and =0Aknow-it-all with Yahoo! =
Mobile. Try it now. http://mobile.yahoo.com/;_ylt=3DAhu06i62sR8H...
cj9tAcJ =0A


1 Answer

Christopher Dicely

2/10/2008 4:53:00 PM

0

Here's my solution. Like others, it uses Newton's method. It may have
problems because it always uses zero as its initial estimate, though
all the test data I've thrown at it seems to work properly. The one
thing that is different than the other solutions I've seen posted is
that I wrapped everything up in a class. This is also my first quiz.

class IncomeStream
DEFAULT_TOLERANCE = 0.000_000_05

def self.irr(*flows)
self.new(flows).irr
end

def self.npv(discount_rate, *flows)
self.new(flows).npv(discount_rate)
end

def self.dpv(amount, time)
lambda {|rate| (-time) * amount * (1+rate)**(-time-1)}
end

def self.pv(amount, time)
lambda {|rate| amount * (1+rate)**(-time)}
end

def initialize(flows)
@flows = flows.to_a
if (not @flows.empty?) and (@flows.first.kind_of? Numeric)
@flows.each_index {|idx| @flows[idx]=[@flows[idx],idx]}
end
@pvs = @flows.map {|amount, time| IncomeStream.pv(amount, time)}
@dpvs = @flows.map {|amount, time| IncomeStream.dpv(amount, time)}
end

def npv(rate)
@pvs.inject(0) {|npv, item| npv+item.call(rate)}
end

def dnpv(rate)
@dpvs.inject(0) {|dnpv, item| dnpv+item.call(rate)}
end

def irr(tolerance=DEFAULT_TOLERANCE)
return nil if @flows.empty? or @flows.all? {|amount, time| amount = 0}
rate = 0.0
while (((n=npv(rate)).abs > tolerance) and rate.finite?)
d = dnpv(rate)
rate -= n/d
end
rate
end