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[]