Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"
 
PerlMonks  

Re: Behold! The power of recursion.

by tachyon (Chancellor)
on Oct 18, 2004 at 02:44 UTC ( #400033=note: print w/ replies, xml ) Need Help??


in reply to Behold! The power of recursion.

It is something of an axiom that any recursive solution can be rewritten as an iterative one. Often a finite infinite loop is useful:

#!/usr/bin/perl -w use constant HIGH => 10_000; my $ans = int(rand(HIGH)) + 1; my ( $lower, $higher ) = (1, HIGH); while(1) { my $guess = int(($lower + $higher)/2); print "Guessing: $guess\n"; last if $ans == $guess; if ( $guess > $ans ) { print "Lower..."; $higher = $guess -1; } else { print "Higher..."; $lower = $guess +1; } } print "The guess was correct!";

FWIW, with your code &function(args) syntax is not considered best style, you can drop the & - which you actually do in the sub. A consistent style is a good idea. You could declare and set $ans in one call.

It is worth noting that while an iterative solution will almost inevitably run faster than a recursive solution, a good recursive solution is often quite terse. A classic very simple example is the calculation of factorial n! The factorial is defined n! = 1 x 2 x 3 x .... (n-1) x n You can code using either iteration or recursion.....

sub fact_rec{ my ($num) = @_; $num ? $num*fact_rec($num-1) : 1 } sub fact_it{ my ($num) = @_; my $fac = 1; for my $i( 1 .. $num ) { $fac *= $i; } return $fac; } for (1..10){ printf"%d!\t%10d\t%10d\n", $_, fact_rec($_), fact_it($_); }

As you can see the recursive solution is short and sweet. It also has a bug that can cause it to go infinite. One gotcha with recursion is that you need to be *positive* that your exit condition (ie stop recursing when we are done) will be *always* be met. A typical real world use for recursion is in dealing with tree like structures
The bug:Negative numbers or floats mean that $num -1 will never equal 0, and so always it will always be true.

cheers

tachyon


Comment on Re: Behold! The power of recursion.
Select or Download Code
Re^2: Behold! The power of recursion.
by pg (Canon) on Oct 18, 2004 at 03:16 UTC
    "It is worth noting that while an iterative solution will almost inevitably run faster than a recursive solution, a good recursive solution is often quite terse."

    Fully agree. Although this demos recursion, it is not a good example to demo the NEED of recursion.

    A typical situation where recursion becomes a clearer solution is that, you need complex stack data structure to remember things otherwise, which is not the case here.

    "A classic very simple example is the calculation of factorial n!"

    My favorite is Hanoi Tower problem.

Re^2: Behold! The power of recursion.
by jordanh (Chaplain) on Oct 18, 2004 at 03:24 UTC
      It is worth noting that while an iterative solution will almost inevitably run faster than a recursive solution, a good recursive solution is often quite terse.

    It's further worth noting that DigitalKitty's algorithm uses only simple tail recursion, which can be easily compiled to be as fast or faster than an iterative solution.

    Although I'm no expert, I believe the compiler would actually have to be smarter to optimize your iterative solution compared to the tail recursive one. Making the inference that $lower and $higher are candidates for register variables is slightly easier to make in the tail recursive version as there is a tendency to use registers for the subroutine calls variables for low-arity functions.

    I could be wrong there, but a good compiler could do about as well with either, I would bet.

    Now, implementing full tail call elimination is trickier, but recognizing tail recursion in this case and performing the optimization is a fairly trivial thing to do. Of course, we are talking about perl code here, and perl does not perform this optimization...

      I believe

      Benchmark knows.

      Benchmark: timing 1000000 iterations of iterative_c, iterative_p, recu +rsive_c, recursive_p... iterative_c: 1 wallclock secs ( 1.10 usr + 0.00 sys = 1.10 CPU) @ 9 +07441.02/s (n=1000000) iterative_p: 19 wallclock secs (19.52 usr + 0.00 sys = 19.52 CPU) @ 5 +1234.76/s (n=1000000) recursive_c: 1 wallclock secs ( 1.16 usr + 0.00 sys = 1.16 CPU) @ 8 +60585.20/s (n=1000000) recursive_p: 36 wallclock secs (36.26 usr + 0.00 sys = 36.26 CPU) @ 2 +7576.32/s (n=1000000) Rate recursive_p iterative_p recursive_c iterative_c recursive_p 27576/s -- -46% -97% -97% iterative_p 51235/s 86% -- -94% -94% recursive_c 860585/s 3021% 1580% -- -5% iterative_c 907441/s 3191% 1671% 5% --
        Benchmark cannot "know" what my hypothetical "good" compiler would do. Perhaps I'm optimistic about the state of compiler technology, but I see no reason why a good compiler wouldn't create the same code for both.

        In the interest of disclosure, what compiler and optimization levels were used in the C case above?

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://400033]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others lurking in the Monastery: (6)
As of 2014-12-22 11:24 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    Is guessing a good strategy for surviving in the IT business?





    Results (116 votes), past polls