in reply to Re^2: fibonacci numbers using subroutine?
in thread fibonacci numbers using subroutine?

Interesting. I ran same benchmark as I'd run previously. Of course I cranked up the number of iterations and took the slow recursive version out of the mix otherwise I'd have time to go have a vacation in Mexico or something!

For run #1, as more of an apples to apples deal, I flushed the cache after each subroutine call. The memoized version wound up about 1/2 the speed (1495/3478) of the iterative version which is a pretty impressive result considering how incredibly slow the non-memoized version is!

Then for run #2, I commented out the line with the "flush" and let fib_memo do its best. Not surprisingly the iterative version stayed the same while the memoized version sped up (4130/3516).

My curiosity is satisfied, but code is below if anybody wants to fiddle with it.

#!/usr/bin/perl -w use strict; use Benchmark; use Memoize qw(flush_cache memoize); use feature "state"; memoize ('fib_memo'); timethese (10000, { Normal=> q{ foreach (20..25) { #print "number $_ : fibonacci ",fibonacci($_),"\n"; my $f = fibonacci($_); } }, # Slow => # q{ # foreach (20..25) # { # #print "number $_ : fibonacci ",fibonacci_slow($_),"\n"; # my $f = fibonacci_slow($_); # } # }, Memo => q{ foreach (20..25) { #print "number $_ : fibonacci ",fib_memo($_),"\n"; my $f = fib_memo($_); flush_cache('fib_memo'); } }, } ); =prints Benchmark: timing 10000 iterations of Memo, Normal... Memo: 7 wallclock secs ( 6.69 usr + 0.00 sys = 6.69 CPU) @ 14 +95.44/s (n=10000) Normal: 3 wallclock secs ( 2.88 usr + 0.00 sys = 2.88 CPU) @ 34 +78.26/s (n=10000) Just for fun...without flush_cache('fib_memo'); Benchmark: timing 10000 iterations of Memo, Normal... Memo: 2 wallclock secs ( 2.42 usr + 0.00 sys = 2.42 CPU) @ 41 +30.52/s (n=10000) Normal: 3 wallclock secs ( 2.84 usr + 0.00 sys = 2.84 CPU) @ 35 +16.17/s (n=10000) =cut sub fibonacci { my $number = shift; my $curnum = 1; my $prevnum = 1; my $sum; if ($number ==1 || $number ==2){ return 1;} $number -= 2; while ($number--) { $sum = $curnum + $prevnum; $prevnum = $curnum; $curnum = $sum; } return $sum; } sub fibonacci_slow { my $number = shift; if ($number ==1 || $number ==2){ return 1;} return fibonacci_slow($number-1) + fibonacci_slow($number-2); } sub fib_memo { state $memo = { 1 => 1, 2 => 1 }; return $memo->{ $_[0] } //= fib_memo( $_[0] - 1 ) + fib_memo( $_[0 +] - 2 ); }

Replies are listed 'Best First'.
Re^4: fibonacci numbers using subroutine?
by BrowserUk (Patriarch) on Aug 20, 2010 at 12:53 UTC

    You don't need to Memoize fib_memo(), the memoisation is already built in! That's what the state variable %memo is for.

    Once you remove that, the real performace shows up (This is for (1..100)):

    c:\test>junk21 Benchmark: timing 10000 iterations of Memo, Normal... Memo: 1 wallclock secs ( 0.64 usr + 0.00 sys = 0.64 CPU) @ 15 +649.45/s (n=10000) Normal: 15 wallclock secs (14.98 usr + 0.01 sys = 14.99 CPU) @ 66 +7.07/s (n=10000)

    The difference is all the clearer with my preferred cmpthese() (why do you use timethese()?):

    c:\test>junk21 Rate Normal Memo Normal 669/s -- -96% Memo 15573/s 2229% --
      timethese() got used instead of cmpthese() because I just cut-n-pasted into some other boiler plate that I had. I also like the cmpthese() format better.

      I guess you must have a 64bit processor? I can't represent fib(100) as an int without resorting to some bigger than normal integer strategy.

        2**68 < Fib(100) == 354224848179261915075 < 2**69

        I do have 64-bit ints, but that shouldn't stop you from doing fib(100). It just rolls over to using floats (with loss of accuracy obviously). You should be able to go all the way to 1476:

        1 : 1 2 : 1 3 : 2 4 : 3 5 : 5 6 : 8 7 : 13 98 : 135301852344706760000 99 : 218922995834555200000 100 : 354224848179262000000 ... 1476 : 1306989223763398700000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000 1477 : 1