MathGroup Archive 2007

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

Search the Archive

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



  • Prev by Date: Re: Working with factors of triangular numbers.
  • Next by Date: Re: Working with factors of triangular numbers.
  • Previous by thread: Re: Compiled function changes somehow.
  • Next by thread: Re: Compiled function changes somehow.