Re: Compiled function changes somehow.
- To: mathgroup at smc.vnet.net
- Subject: [mg78597] Re: Compiled function changes somehow.
- From: Jean-Marc Gulliet <jeanmarc.gulliet at gmail.com>
- Date: Thu, 5 Jul 2007 04:00:22 -0400 (EDT)
- Organization: The Open University, Milton Keynes, UK
- References: <f6fqn6$8mo$1@smc.vnet.net>
Nacho wrote: > Hello. > > I have been playing with Compile to accelerate some simple code and I > have found some differences that I cannot explain. > > The standard/compiled code is as follows: > > standard[max_] := > Table[n/m, {n, 1, max}, {m, 1, max}] // N // Flatten; > > compiled = > Compile[{{max, _Integer}}, > Table[n/m, {n, 1, max}, {m, 1, max}] // N // Flatten]; > > So I can do the same calculations with both codes: > > In[19]:= standardresult = standard[1000]; // Timing > > Out[19]= {2.969, Null} > > In[20]:= compiledresult = compiled[1000]; // Timing > > Out[20]= {0.422, Null} > > > The second is much faster, as expected. But are the results the same? > Apparently, yes: > > In[21]:= standardresult == compiledresult > > Out[21]= True > > In[22]:= standardresult === compiledresult > > Out[22]= True > > > But when I use Union in the lists to count the number of different > elements, I have this surprise: > > Length[Union[standardresult]] > Length[Union[compiledresult]] > > Out[23]= 608383 > Out[24]= 634815 > > So they are not exactly the same... I think that the correct answer > comes from the uncompiled version. It is the same if I remove the //N > so it can be compared symbolically. > > Is this behaviour expected? Am I missing something? > > Both seem to be Machine Precision, but obviously there are some little > differences. This happens with V5.2 and V6.0. > > Any hint? > > Thank you. The observed difference comes from round-off errors. Note that both versions of the non-compiled function, called 'std' in the code below, compute first all the numbers in exact arithmetic and only then, when required, the rounding is done (in the first case by an explicit call to the built in function *N*, and in the the second by an implicit call to it by the default test comparing values in the function *Union*). Look at the similarity in speed and results between the uncompiled and compiled function in the third version of the code. (* First Test Case: Note that the call to *N* in the compiled version is useless since the computation have been already done in machine precision arithmetic (hence the difference in speed against the uncompiled version). I have kept it for consistency with the original post, however. *) In[1]:= std[max_] := Flatten[N[Table[n/m, {n, 1, max}, {m, 1, max}]]]; cmp = Compile[{{max, _Integer}}, Flatten[N[Table[n/m, {n, 1, max}, {m, 1, max}]]]]; In[3]:= Timing[stdres = std[1000];] Out[3]= {4.516, Null} In[4]:= Timing[cmpres = cmp[1000];] Out[4]= {0.391, Null} In[5]:= {stdres == cmpres, stdres === cmpres} Out[5]= {True, True} In[6]:= {Length[Union[stdres]], Length[Union[cmpres]]} Out[6]= {608383, 634815} In[7]:= {Precision[stdres[[1]]], Precision[cmpres[[1]]]} Out[7]= {MachinePrecision, MachinePrecision} (* Second Test Case *) In[8]:= std[max_] := Flatten[Table[n/m, {n, 1, max}, {m, 1, max}]]; cmp = Compile[{{max, _Integer}}, Flatten[Table[n/m, {n, 1, max}, {m, 1, max}]]]; In[10]:= Timing[stdres = std[1000];] Out[10]= {3.047, Null} In[11]:= Timing[cmpres = cmp[1000];] Out[11]= {0.359, Null} In[12]:= {stdres == cmpres, stdres === cmpres} Out[12]= {True, False} In[13]:= {Length[Union[stdres]], Length[Union[cmpres]]} Out[13]= {608383, 634815} In[14]:= {Precision[stdres[[1]]], Precision[cmpres[[1]]]} Out[14]= {Infinity, MachinePrecision} (* Third Test Case: *N* is inside the *Table* function, forcing the computations according to the machine precision arithmetic model. Note that the speed is now very close to that of the compiled version. *) In[15]:= std[max_] := Flatten[Table[N[n]/m, {n, 1, max}, {m, 1, max}]]; cmp = Compile[{{max, _Integer}}, Flatten[N[Table[n/m, {n, 1, max}, {m, 1, max}]]]]; In[17]:= Timing[stdres = std[1000];] Out[17]= {0.453, Null} In[18]:= Timing[cmpres = cmp[1000];] Out[18]= {0.375, Null} In[19]:= {stdres == cmpres, stdres === cmpres} Out[19]= {True, True} In[20]:= {Length[Union[stdres]], Length[Union[cmpres]]} Out[20]= {634815, 634815} In[21]:= {Precision[stdres[[1]]], Precision[cmpres[[1]]]} Out[21]= {MachinePrecision, MachinePrecision} Regards, Jean-Marc