MathGroup Archive 2004

[Date Index] [Thread Index] [Author Index]

Search the Archive

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/
>


  • Prev by Date: Re: Speed of repeated matrix calculation
  • Previous by thread: Re: Question on Compile[]
  • Next by thread: Re: ListDensityPlot (solution, and critical comment))