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