<?xml version="1.0" encoding="windows-1252"?>
<node id="1013033" title="Reminder to self: must use Memoize more often!" created="2013-01-12 07:13:55" updated="2013-01-12 07:13:55">
<type id="1042">
CUFP</type>
<author id="757127">
tobyink</author>
<data>
<field name="doctext">
&lt;p&gt;For functions which are non-volatile (i.e. the same inputs will always produce the same outputs) with no side-effects, it often makes sense to "memoize" them. That is, cache the results for the next time they're called.&lt;/p&gt;

&lt;p&gt;This is an especially good idea in the case of recursive functions. The following benchmark script illustrates the massive speed up.&lt;/p&gt;

&lt;c&gt;
use strict;
use warnings;
use Memoize;
use Benchmark 'cmpthese';

sub fib1 {
	my $n = shift;
	return $n if $n &lt; 2;
	return fib1($n-1) + fib1($n-2);
}

sub fib2 {
	my $n = shift;
	return $n if $n &lt; 2;
	return fib2($n-1) + fib2($n-2);
}

memoize('fib2');

my %fib3_cache;
sub fib3 {
	my $n = shift;
	return $fib3_cache{$n} ||= do {
		$n &lt; 2 ? $n : fib3($n-1) + fib3($n-2)
	};
}

for (0..5) {
	die "something bad" unless fib1($_)==fib2($_);
	die "something bad" unless fib1($_)==fib3($_);
}

cmpthese(-1, {
	fib1 =&gt; sub { fib1 20 },
	fib2 =&gt; sub { fib2 20 },
	fib3 =&gt; sub { fib3 20 },
});

__END__
         Rate     fib1     fib2     fib3
fib1   18.2/s       --    -100%    -100%
fib2  37594/s  206668%       --     -87%
fib3 289129/s 1590107%     669%       --
&lt;/c&gt;

&lt;p&gt;The [mod://Memoize] module gives you a pretty decent speed up, without needing to change the guts of the function. Just add &lt;c&gt;memoize('fib2')&lt;/c&gt; and the Memoize module will wrap the original function with memoization code.&lt;/p&gt;

&lt;p&gt;The manually memoized version is clearly faster still, because it avoids the overhead of function wrapping - the memoization code is added to the guts of the function.&lt;/p&gt;

&lt;p&gt;Of course, there's no such thing as a free lunch - you're trading CPU for memory.&lt;/p&gt;

&lt;!-- Node text goes above. Div tags should contain sig only --&gt;
&lt;div class="pmsig"&gt;&lt;div class="pmsig-757127"&gt;
&lt;small&gt;&lt;small&gt;
&lt;tt&gt;perl -E'sub Monkey::do{say$_,for@_,do{($monkey=&amp;#x5B;caller(0)]-&gt;&amp;#x5B;3])=~s{::}{ }and$monkey}}"Monkey say"-&gt;Monkey::do'
&lt;/tt&gt;&lt;/small&gt;&lt;/small&gt;
&lt;/div&gt;&lt;/div&gt;</field>
</data>
</node>
