Performance of Nest vs. Do
The main reason why
x = 0.1; Do[x = 3 x (1 - x), 300] // AbsoluteTiming // First
0.000393629
and
lf[x_] := 3 x (1 - x)
x = 0.1; Do[x = lf[x], 300] // AbsoluteTiming // First
Nest[lf[#] &, .1, 300] // AbsoluteTiming // First
0.000643239
0.000691691
are slower than
Nest[3 # (1 - #) &, .1, 300] // AbsoluteTiming // First
0.000161729
is the fact, that the last Nest
can and does make use of autocompilation.
The default NestCompileLength
is 100:
SystemOptions["CompileOptions" -> "NestCompileLength"]
{"CompileOptions" -> {"NestCompileLength" -> 100}}
Autocompilation can be switched off for Nest
by setting its compile length to Infinity
.
SetSystemOptions["CompileOptions" -> "NestCompileLength" -> Infinity]
Now
Nest[3 # (1 - #) &, .1, 300] // AbsoluteTiming // First
0.000461127
is much slower and has a performance similar to the first Do
.
By using a precompiled version of lf
a performance that is even better than the pure function with Nest
's autocompilation can be achieved:
clf = Compile[{{x, _Real, 0}}, 3 x (1 - x)];
Nest[clf, .1, 300] // AbsoluteTiming // First
0.000128982
However, if the time needed for compiling is included
First@AbsoluteTiming[
clf2 = Compile[{{x, _Real, 0}}, 3 x (1 - x)];
Nest[clf2, .1, 300]
]
0.000187792
one can see that this uses more time in total than the pure function with autocompilation, as calling clf2
for every evaluation adds an additional overhead.
After switching autocompilation back on
SetSystemOptions["CompileOptions" -> "NestCompileLength" -> 1];
Nest
does need some extra time, because it tries to autocompile clf
now
Nest[clf, .1, 300] // AbsoluteTiming // First
0.000188127
I get results that differ form yours more than can be accounted form by my computer system being slower than yours. Here is what I'm seeing.
(x = 0.1; Do[x = 3 x (1 - x), 300];x) // AbsoluteTiming
{0.000406, 0.653113}
Nest[3 # (1 - #) &, .1, 300] // AbsoluteTiming
{0.000177, 0.653113}
f[x_] := 3 x (1 - x)
func = Function[Evaluate[f[#]]]
3 (1 - #1) #1 &
(x = 0.1; Do[x = f[x], 300]; x) // AbsoluteTiming
{0.000712, 0.653113}
Nest[f, .1, 300] // AbsoluteTiming
{0.000586, 0.653113}
Nest[func, .1, 300] // AbsoluteTiming
{0.000177, 0.653113}
This last version is exactly the same internally as the 2nd version and, not surprisingly, gives the same results.
Conclusions
Nest
is alway faster thanDo
.Nest
is optimized for pure functions.- When you want to iterate over user defined function, when feasible it is best to convert it into a pure function and iterate over the pure function.