Re: Question on Compile[]
- To: mathgroup at smc.vnet.net
- Subject: [mg49789] Re: [mg49747] Question on Compile[]
- From: Andrzej Kozlowski <akoz at mimuw.edu.pl>
- Date: Sat, 31 Jul 2004 03:14:11 -0400 (EDT)
- References: <200407301002.GAA26336@smc.vnet.net> <8F615E95-E269-11D8-B488-000A95B4967A@mimuw.edu.pl>
- Sender: owner-wri-mathgroup at wolfram.com
While I still do not know for sure if the problem I have been addressing is really the one you have encountered, I have thought of a rather obvious solution. The idea is to replace the code: dcf1 = Compile[{{cashFlow, _Real, 1}, {rate, _Real}}, Module[{nvec = Range[ Length[cashFlow]]}, Total[cashFlow/(1.0 + rate)^nvec] ]] by a version in which you simply replace 1/(1.0 + rate) by its Taylor expansion. You can take quite many terms and still retain good speed. For example, lets compare the following two codes: dcf[cashFlow_, rate_] := Module[{nvec = Range[Length[cashFlow]]}, Total[cashFlow/(1.0 + rate)^nvec] ] with the following compiled one: dcf2 = Compile[{{cashFlow, _Real, 1}, {rate, _Real}}, Module[{nvec = Range[Length[cashFlow]]}, Total[cashFlow*(-rate^19 + rate^18 - rate^17 + rate^16 - rate^15 + rate^14 - rate^13 + rate^12 - rate^11 + rate^10 - rate^9 + rate^8 - rate^7 + rate^6 - rate^5 + rate^4 - rate^3 + rate^2 - rate + 1)^nvec]]]; As before we take cashFlow[n_]:=Table[Random[],{n}]; cc=cashFlow[10000]; r=0.1; Now dcf[cc,r]//Timing {0.29 Second,3.8267} While dcf2[cc,r]//Timing {0.02 Second,3.8267} The answers are very close but the speed difference is considerable! Andrzej On 30 Jul 2004, at 22:46, Andrzej Kozlowski wrote: > On 30 Jul 2004, at 12:02, Mark Coleman wrote: > >> >> Greetings, >> >> I am doing some research in finance, translating some visual basic >> code >> into Mathematica, and attempting to optimize it. Most of this is quite >> straightforward, and by Compiling[] functions, execution is quite >> fast. >> I did run into an instance where the compilied code ran a bit slower >> than the uncompiled code. I am sure this has something to do with some >> additional work that Mathematica is doing internally to expand the >> expression I >> am using, but I was hoping someone on the list could help me >> understand >> and if possible fix, this behavior. >> >> Specifically I am calculating a standard discounted cash flow. The >> computation is quite simple, Let >> >> cashFlow be a list of real numbers of length n and let nvec=Range[n], >> then the discounted cash flow is the sum over i=1,n of >> >> cashFlow(i)/(1+r)^i >> >> where r is a real number with 0 < r < 1. >> >> The final Mathematica code is: >> >> >> Clear[dcf]; >> dcf[cashFlow_, rate_] := Module[{nvec = Range[Length[cashFlow]]}, >> Total[cashFlow/(1.0 + rate)^nvec] >> ] >> >> >> On my 800 Mhz Powerbook G4, 5000 trials of this takes 3.72 seconds, >> while the compiled version takes 4.2 seconds. >> >> Any ideas how I can speed this up, to get the usual gains one >> typically >> sees in compiled code? >> >> Thanks, >> >> -Mark >> >> > > Here is what I see on my machine (also a Mac PowerBook): > > We compare two functions: > > dcf[cashFlow_, rate_] := Module[{nvec = Range[Length[cashFlow]]}, > Total[cashFlow/(1.0 + rate)^nvec] > ] > > > dcf1 = Compile[{{cashFlow, _Real, 1}, {rate, _Real}}, Module[{nvec = > Range[ > Length[cashFlow]]}, > Total[cashFlow/(1.0 + rate)^nvec] > ]] > > Lets also define > > cashFlow[n_]:=Table[Random[],{n}]; > > and lets take > r=0.1; > > Now try > > cc=cashFlow[5000]; > > > dcf[cc,r]//Timing > {0.01 Second,5.65194} > > > dcf1[cc,r]//Timing > {0. Second,5.65194} > > As expected the compiled code is faster. The problem occurs only when > we take a larger n > > In[39]:= > cc=cashFlow[8000]; > > > dcf[cc,r]//Timing > > > {0.15 Second,4.39072} > > > dcf1[cc,r]//Timing > > > "Numerical error encountered at > instruction 1; proceeding with uncompiled evaluation. > > {0.19 Second,4.39072} > > So it is not the case here that the compiled code is slower, rather an > error occurred and a non-compiled version of the function was used. I > think the reason why it fails is that in the body of your function you > have numbers of the form > > c/(rate + 1.)^v > > and when v becomes very large 1/(rate + 1.)^v becomes smaller than > $MinMachineNumber . Since Compile can only work with numerical > quantities that satisfy the usual restriction on machine arithmetic > the compiled function cannot be used and Mathematica switches to > compiled code. Having considered this only briefly I can't yet see as > yet any very satisfactory remedy. The only one I can think of is based > on breaking your function into a linear combination of functions, each > of which is compiled separately in such a way that no numbers smaller > than $MinMachineNumber occur during the computation. Unfortunately > the splitting will have to depend on the length of cashFlow, and it > may be tricky to write such a function that would avoid above > difficulty for all n. > > All this assumes that the problem you have encountered is the same > one I have been discussing. That is not quite obvious from your > posting since you do not mention getting any messages about > "proceeding with uncompiled evaluation". It may be that there is > something I have misunderstood. > > > Andrzej Kozlowski > Chiba, Japan > http://www.mimuw.edu.pl/~akoz/ >
- References:
- Question on Compile[]
- From: Mark Coleman <mark@markscoleman.com>
- Question on Compile[]