23
1 CS 410 Mastery in Programming Chapter 2 Recursion Herbert G. Mayer, PSU CS Herbert G. Mayer, PSU CS status 7/3/2011 status 7/3/2011

1 CS 410 Mastery in Programming Chapter 2 Recursion Herbert G. Mayer, PSU CS status 7/3/2011

  • View
    228

  • Download
    1

Embed Size (px)

Citation preview

Page 1: 1 CS 410 Mastery in Programming Chapter 2 Recursion Herbert G. Mayer, PSU CS status 7/3/2011

1

CS 410Mastery in Programming

Chapter 2Recursion

Herbert G. Mayer, PSU CSHerbert G. Mayer, PSU CSstatus 7/3/2011status 7/3/2011

Page 2: 1 CS 410 Mastery in Programming Chapter 2 Recursion Herbert G. Mayer, PSU CS status 7/3/2011

2

Syllabus Definition of RecursionDefinition of Recursion

Recursion vs. IterationRecursion vs. Iteration

Q-SequenceQ-Sequence

Ackermann FunctionAckermann Function

Simulate Recursion via IterationSimulate Recursion via Iteration

ReferencesReferences

Page 3: 1 CS 410 Mastery in Programming Chapter 2 Recursion Herbert G. Mayer, PSU CS status 7/3/2011

3

Definition of RecursionAn algorithms is recursive, if it is An algorithms is recursive, if it is partlypartly defined in simpler versions of itself [1] defined in simpler versions of itself [1]

A recursive program is the implementation of a recursive algorithm What if a programming language is non-recursive (e.g. Fortran) and we wish to express a

recursive algorithm (e.g. parsing) in that very language? --See later!

What then are the What then are the other partsother parts of a recursive algorithm? of a recursive algorithm? A correctly defined recursive algorithm requires a starting point, formally known as the

“base case” Base case could be multiple steps

Recursive algorithm A() uses a base case as origin of computation, plus the actual, Recursive algorithm A() uses a base case as origin of computation, plus the actual, recursive function body, including some recursive use of A()recursive function body, including some recursive use of A()

Recursive body can be Recursive body can be indirectly recursiveindirectly recursive through intermediate function through intermediate function a()-> b()-> a() – through intermediate function b()

Primitive examples are the factorial( n ) function; or Fibonacci( n ), for non-negative Primitive examples are the factorial( n ) function; or Fibonacci( n ), for non-negative arguments n; the latter shown here:arguments n; the latter shown here:

Base case 1: Fibo(0) = 0 Base case 2: Fibo(1) = 1 Recursive Definition: Fibo( n ) for n > 1 = Fibo( n-1 ) + Fibo( n-2 )

Page 4: 1 CS 410 Mastery in Programming Chapter 2 Recursion Herbert G. Mayer, PSU CS status 7/3/2011

4

Recursion vs. Iteration

Iteration is expressed in programming languages by Iteration is expressed in programming languages by loops; e.g. loops; e.g. for-, while-, do-, repeatfor-, while-, do-, repeat loops loops

These are readable and efficient methods for These are readable and efficient methods for expressing iteration, but are not necessaryexpressing iteration, but are not necessary

Recursion can easily replace such iterative steps; yet Recursion can easily replace such iterative steps; yet for some people this seems hard to understandfor some people this seems hard to understand

In reality, people are simply unused to recursion; else In reality, people are simply unused to recursion; else recursion would be as immediately understandable recursion would be as immediately understandable as iterationas iteration

Page 5: 1 CS 410 Mastery in Programming Chapter 2 Recursion Herbert G. Mayer, PSU CS status 7/3/2011

5

Q-Sequence, DefinitionQ-Sequence is defined in [1] as a function q(n) for positive integers nQ-Sequence is defined in [1] as a function q(n) for positive integers n

Base case 1: q(1) = 1Base case 1: q(1) = 1Base case 2: q(2) = 1Base case 2: q(2) = 1

Recursive definition of q(n), for n > 2Recursive definition of q(n), for n > 2

q( n ) = q( n – q( n-1 ) ) + q( n – q( n-2 ) )q( n ) = q( n – q( n-1 ) ) + q( n – q( n-2 ) )

Q-Sequence reminds us of Q-Sequence reminds us of Fibonacci( n )Fibonacci( n ) function, but with a great function, but with a great difference in type of result:difference in type of result:

The function results of The function results of Fibonacci( n )Fibonacci( n ) are monotonically increasing are monotonically increasing with increasing argumentwith increasing argument

Yet surprisingly, the results of Yet surprisingly, the results of q( n )q( n ) are non-monotonic! are non-monotonic!

Note # of calls:Note # of calls: calls( q( 40 ) ) = 1,137,454,741 calls( q( 40 ) ) = 1,137,454,741

Page 6: 1 CS 410 Mastery in Programming Chapter 2 Recursion Herbert G. Mayer, PSU CS status 7/3/2011

6

Q-Sequence, Coded in C#define MAX 100#define MAX 100 // arbitrary limit// arbitrary limitint calls;int calls; // will be initialized each time// will be initialized each time

int q( int arg )int q( int arg ){ // q{ // q

calls++;calls++; // track another call// track another callif ( arg <= 2 ) {if ( arg <= 2 ) { return 1;return 1; // base case// base case}else{}else{ // now recurse!// now recurse! return q( arg - q( arg-1) ) + q( arg - q( arg-2) );return q( arg - q( arg-1) ) + q( arg - q( arg-2) );} //end if} //end if

} //end q} //end q

void main()void main(){ // main{ // main

for ( int i = 1; i < MAX; i++ ) {for ( int i = 1; i < MAX; i++ ) { calls = 0;calls = 0; // initially no calls yet// initially no calls yet printf( "Q(%2d) = %3d, #calls = %10d\n", i, q(i), printf( "Q(%2d) = %3d, #calls = %10d\n", i, q(i), calls );calls );} //end for} //end for

} // end main} // end main

Page 7: 1 CS 410 Mastery in Programming Chapter 2 Recursion Herbert G. Mayer, PSU CS status 7/3/2011

7

Q-Sequence ResultsQ( 1) = 1, #calls = 1Q( 1) = 1, #calls = 1Q( 2) = 1, #calls = 1Q( 2) = 1, #calls = 1Q( 3) = 2, #calls = 5Q( 3) = 2, #calls = 5Q( 4) = 3, #calls = 13Q( 4) = 3, #calls = 13Q( 5) = 3, #calls = 25Q( 5) = 3, #calls = 25Q( 6) = 4, #calls = 49Q( 6) = 4, #calls = 49Q( 7) = 5, #calls = 93Q( 7) = 5, #calls = 93Q( 8) = 5, #calls = 161Q( 8) = 5, #calls = 161Q( 9) = 6, #calls = 281Q( 9) = 6, #calls = 281Q(10) = 6, #calls = 481Q(10) = 6, #calls = 481Q(11) = 6, #calls = 813Q(11) = 6, #calls = 813

. . .. . .

Q(26) = 14, #calls = 1341433Q(26) = 14, #calls = 1341433Q(27) = 16, #calls = 2174493Q(27) = 16, #calls = 2174493Q(28) = 16, #calls = 3521137Q(28) = 16, #calls = 3521137Q(29) = 16, #calls = 5700281Q(29) = 16, #calls = 5700281Q(30) = 16, #calls = 9229053Q(30) = 16, #calls = 9229053Q(31) = 20, #calls = 14941993Q(31) = 20, #calls = 14941993Q(32) = 17, #calls = 24182797Q(32) = 17, #calls = 24182797Q(33) = 17, #calls = 39137473Q(33) = 17, #calls = 39137473Q(34) = 20, #calls = 63354153Q(34) = 20, #calls = 63354153Q(35) = 21, #calls = 102525697Q(35) = 21, #calls = 102525697Q(36) = 19, #calls = 165896537Q(36) = 19, #calls = 165896537Q(37) = 20, #calls = 268460333Q(37) = 20, #calls = 268460333Q(38) = 22, #calls = 434429737Q(38) = 22, #calls = 434429737Q(39) = 21, #calls = 702952137Q(39) = 21, #calls = 702952137Q(40) = 22, #calls = 1137454741Q(40) = 22, #calls = 1137454741

. . . Will never reach 100 in your life time . . . Will never reach 100 in your life time

Page 8: 1 CS 410 Mastery in Programming Chapter 2 Recursion Herbert G. Mayer, PSU CS status 7/3/2011

8

Ackermann Definition

Ackermann a( m, n ) is defined as a function Ackermann a( m, n ) is defined as a function of two non-negative integers m and nof two non-negative integers m and n

Base case 1: a( 0, n ) = n+1Base case 1: a( 0, n ) = n+1Base case 2: a( m, 0 ) = a( m-1, 1 )Base case 2: a( m, 0 ) = a( m-1, 1 )

Recursive definition of a( m, n ), m, n > 0Recursive definition of a( m, n ), m, n > 0a( m, n ) = a( m-1, a( m, n-1 ) )a( m, n ) = a( m-1, a( m, n-1 ) )

Ackermann grows awfully fast. For example:Ackermann grows awfully fast. For example:aa(4,2) is integer with 19,729 decimal digits (4,2) is integer with 19,729 decimal digits

Page 9: 1 CS 410 Mastery in Programming Chapter 2 Recursion Herbert G. Mayer, PSU CS status 7/3/2011

9

Ackermann Coded in Cunsigned a( unsigned m, unsigned n )unsigned a( unsigned m, unsigned n ){ // a{ // a

calls++;calls++; // global unsigned// global unsignedif ( 0 == m ) {if ( 0 == m ) { return n + 1;return n + 1; // a base case// a base case}else if ( 0 == n ) {}else if ( 0 == n ) { // m > 0// m > 0

return a( m-1, 1 );return a( m-1, 1 ); // other base case// other base case}else{}else{ // m > 0, n > 0// m > 0, n > 0

return a( m-1, a( m, n-1 ) );return a( m-1, a( m, n-1 ) ); // recurse// recurse} //end if} //end if

} //end q} //end q

void main()void main(){ // main{ // main

for( int i = 0; i < MAX; i++ ) {for( int i = 0; i < MAX; i++ ) { printf( "\nFor m = %d\n", i );printf( "\nFor m = %d\n", i ); for( int j = 0; j < MAX; j++ ) {for( int j = 0; j < MAX; j++ ) {

calls = 0;calls = 0; printf( "a(%1d,%1d) = %10u, calls = %12u\n",printf( "a(%1d,%1d) = %10u, calls = %12u\n",

i, j, a( i, j ), calls );i, j, a( i, j ), calls ); } //end for} //end for

} //end for} //end for} // end main} // end main

Page 10: 1 CS 410 Mastery in Programming Chapter 2 Recursion Herbert G. Mayer, PSU CS status 7/3/2011

10

Ackermann ResultsFor m = 0For m = 0a(0,0) = 1, calls = 1a(0,0) = 1, calls = 1. . .. . .

For m = 1For m = 1. . .. . .a(1,7) = 9, calls = 16a(1,7) = 9, calls = 16

For m = 2For m = 2a(2,0) = 3, calls = 5a(2,0) = 3, calls = 5a(2,1) = 5, calls = 14a(2,1) = 5, calls = 14a(2,2) = 7, calls = 27a(2,2) = 7, calls = 27a(2,3) = 9, calls = 44a(2,3) = 9, calls = 44a(2,4) = 11, calls = 65a(2,4) = 11, calls = 65a(2,5) = 13, calls = 90a(2,5) = 13, calls = 90a(2,6) = 15, calls = 119a(2,6) = 15, calls = 119a(2,7) = 17, calls = 152a(2,7) = 17, calls = 152

For m = 3For m = 3a(3,0) = 5, calls = 15a(3,0) = 5, calls = 15a(3,1) = 13, calls = 106a(3,1) = 13, calls = 106a(3,2) = 29, calls = 541a(3,2) = 29, calls = 541a(3,3) = 61, calls = 2432a(3,3) = 61, calls = 2432a(3,4) = 125, calls = 10307a(3,4) = 125, calls = 10307a(3,5) = 253, calls = 42438a(3,5) = 253, calls = 42438a(3,6) = 509, calls = 172233a(3,6) = 509, calls = 172233a(3,7) = 1021, calls = 693964a(3,7) = 1021, calls = 693964

For m = 4For m = 4a(4,0) = 13, calls = 107a(4,0) = 13, calls = 107

don’t even dream about computing a(4,2) don’t even dream about computing a(4,2) or higher! or higher!

Page 11: 1 CS 410 Mastery in Programming Chapter 2 Recursion Herbert G. Mayer, PSU CS status 7/3/2011

11

Simulate Recursion via Iteration

What to do, if you implement a recursive algorithm What to do, if you implement a recursive algorithm using a language that does not support recursion?using a language that does not support recursion?

Replace the recursive by a non-recursive algorithm!Replace the recursive by a non-recursive algorithm!

Or simulate recursion via non-recursive methodsOr simulate recursion via non-recursive methods

After all, a computer chip has no notion of recursion; it After all, a computer chip has no notion of recursion; it is a sequential machine that “simulates recursion” is a sequential machine that “simulates recursion” via non-recursive methods; compiler maps!via non-recursive methods; compiler maps!

Done so frequently in industry; e.g. FPS used Fortran to Done so frequently in industry; e.g. FPS used Fortran to implement System SW and compilersimplement System SW and compilers

Here are the actual steps of simulating recursion via Here are the actual steps of simulating recursion via iteration:iteration:

Page 12: 1 CS 410 Mastery in Programming Chapter 2 Recursion Herbert G. Mayer, PSU CS status 7/3/2011

12

Steps of Simulating Recursionconsider directly-recursive calls, i.e. calls from within recursive consider directly-recursive calls, i.e. calls from within recursive

function:function:

1.1. Define explicit stack with Define explicit stack with top of stacktop of stack (tos) index, initially 0; like (tos) index, initially 0; like a real stack, it may overflow, include code to check; holds all a real stack, it may overflow, include code to check; holds all parameters, function return value, return location (labels after a parameters, function return value, return location (labels after a recursive call)recursive call)

2.2. Define labels for each Define labels for each point of recursive callpoint of recursive call, and each , and each point of point of returnreturn; number these labels, for example l1, l2, l3 etc. There will ; number these labels, for example l1, l2, l3 etc. There will be branches to the be branches to the points of returnpoints of return

3.3. At each point ofAt each point of recursive call recursive call:: Increment the tos Move parameters for “this call” onto stack; e.g. stack[ tos ].arg1 = … Store place of return; e.g. stack[ tos ].ret = 1, 2, 3

alluding to labels l1, l2, l3 Jump to the head of the function, not including initializing code

Page 13: 1 CS 410 Mastery in Programming Chapter 2 Recursion Herbert G. Mayer, PSU CS status 7/3/2011

13

Steps of Simulating Recursion

4. Ideally, all explicitly coded returns and the implied return at 4. Ideally, all explicitly coded returns and the implied return at the end of the recursive function body can be re-coded into a the end of the recursive function body can be re-coded into a single place; if not, the code before each return is replicated:single place; if not, the code before each return is replicated: Decrement the top of stack index Check, to which of the stored labels the flow of control has to

branch to continue execution; e.g.:

if ( stack[ tos ].ret == xyz ) goto label_xyz; And if no other branch is open, then fall through the end For void functions this is a literal fall-through For true functions, the return value has to be computed, e.g.:

stack[ tos ].return_val = …

5. For nested recursive calls or several recursive calls in a row 5. For nested recursive calls or several recursive calls in a row or both: “be creative” or both: “be creative”

Page 14: 1 CS 410 Mastery in Programming Chapter 2 Recursion Herbert G. Mayer, PSU CS status 7/3/2011

14

Simulate Recursion, fact()#include <stdio.h>#include <stdio.h>#define MAX_STACK 100#define MAX_STACK 100 // never reached or exceeded!// never reached or exceeded!#define MAX 14#define MAX 14 // higher factorials overflow 32b// higher factorials overflow 32b

unsigned calls;unsigned calls; // in case we track # of calls// in case we track # of calls

typedef struct s_tp {typedef struct s_tp {unsigned arg;unsigned arg;unsigned fact;unsigned fact;unsigned ret;unsigned ret;

} struct_s_tp;} struct_s_tp;

// first the recursive fact() function for reference// first the recursive fact() function for reference// includes tracking # of calls// includes tracking # of callsunsigned fact( unsigned arg )unsigned fact( unsigned arg ){ // fact{ // fact

calls++;calls++; // gotta be global// gotta be globalif ( 0 == arg ) {if ( 0 == arg ) { return 1;return 1;}else{}else{ return fact( arg - 1 ) * arg;return fact( arg - 1 ) * arg;} //end if} //end if

} //end fact} //end fact

Page 15: 1 CS 410 Mastery in Programming Chapter 2 Recursion Herbert G. Mayer, PSU CS status 7/3/2011

15

Simulate Recursion, fact()unsigned nrfact( unsigned arg )unsigned nrfact( unsigned arg ){ //nrfact{ //nrfact

struct_s_tp s[ MAX_STACK ];struct_s_tp s[ MAX_STACK ]; // local stack, no // local stack, no recursion!recursion!unsigned top = 0;unsigned top = 0;s[ top ].arg = arg;s[ top ].arg = arg; // this call’s argument// this call’s arguments[ top ].ret = 3;s[ top ].ret = 3; // 3 alludes to label l3// 3 alludes to label l3

l1:l1: if ( 0 == s[ top ].arg ) {if ( 0 == s[ top ].arg ) { s[ top ].fact = 1;s[ top ].fact = 1;}else{}else{ top++;top++; // recurse soon// recurse soon s[ top ].arg = s[ top-1 ].arg-1;s[ top ].arg = s[ top-1 ].arg-1; s[ top ].ret = 2;s[ top ].ret = 2; // remember label l2// remember label l2 goto l1;goto l1; // here simulate recursion// here simulate recursion

l2:l2: // back from recursive call.// back from recursive call. top--;top--; // back from call// back from call s[ top ].fact = s[ top + 1 ].fact * s[ top ].arg;s[ top ].fact = s[ top + 1 ].fact * s[ top ].arg;} //end if} //end ifif ( s[ top ].ret == 2 ) {if ( s[ top ].ret == 2 ) { // test, where to branch to// test, where to branch to goto l2;goto l2; // unstructured goto into if// unstructured goto into if} //end if} //end if

l3:l3:return s[ top ].fact;return s[ top ].fact;

} //end nrfact} //end nrfact

Page 16: 1 CS 410 Mastery in Programming Chapter 2 Recursion Herbert G. Mayer, PSU CS status 7/3/2011

16

Simulate Recursion, fact() Results r_fact( 0) = 1, calls = 1r_fact( 0) = 1, calls = 1 r_fact( 1) = 1, calls = 2 r_fact( 1) = 1, calls = 2 r_fact( 2) = 2, calls = 3 r_fact( 2) = 2, calls = 3 r_fact( 3) = 6, calls = 4 r_fact( 3) = 6, calls = 4 r_fact( 4) = 24, calls = 5 r_fact( 4) = 24, calls = 5 r_fact( 5) = 120, calls = 6 r_fact( 5) = 120, calls = 6 r_fact( 6) = 720, calls = 7 r_fact( 6) = 720, calls = 7 r_fact( 7) = 5040, calls = 8 r_fact( 7) = 5040, calls = 8 r_fact( 8) = 40320, calls = 9 r_fact( 8) = 40320, calls = 9 r_fact( 9) = 362880, calls = 10 r_fact( 9) = 362880, calls = 10 r_fact(10) = 3628800, calls = 11 r_fact(10) = 3628800, calls = 11 r_fact(11) = 39916800, calls = 12 r_fact(11) = 39916800, calls = 12 r_fact(12) = 479001600, calls = 13 r_fact(12) = 479001600, calls = 13 r_fact(13) = 1932053504, calls = 14 r_fact(13) = 1932053504, calls = 14

nr_fact( 0) = 1nr_fact( 0) = 1nr_fact( 1) = 1nr_fact( 1) = 1nr_fact( 2) = 2nr_fact( 2) = 2nr_fact( 3) = 6nr_fact( 3) = 6nr_fact( 4) = 24nr_fact( 4) = 24nr_fact( 5) = 120nr_fact( 5) = 120nr_fact( 6) = 720nr_fact( 6) = 720nr_fact( 7) = 5040nr_fact( 7) = 5040nr_fact( 8) = 40320nr_fact( 8) = 40320nr_fact( 9) = 362880nr_fact( 9) = 362880nr_fact(10) = 3628800nr_fact(10) = 3628800nr_fact(11) = 39916800nr_fact(11) = 39916800nr_fact(12) = 479001600nr_fact(12) = 479001600nr_fact(13) = 1932053504nr_fact(13) = 1932053504

Page 17: 1 CS 410 Mastery in Programming Chapter 2 Recursion Herbert G. Mayer, PSU CS status 7/3/2011

17

Simulate Recursion, fibo()#define MAX_STACK 100#define MAX_STACK 100 // never to be reached or exceeded!// never to be reached or exceeded!#define MAX 30#define MAX 30 // higher fibo(n) not computed// higher fibo(n) not computed

unsigned calls;unsigned calls; // in case we track # of calls// in case we track # of calls

typedef struct s_tp {typedef struct s_tp { // type of stack// type of stackunsigned arg;unsigned arg; // copy of fibo’s arg// copy of fibo’s argunsigned fibo;unsigned fibo; // return value for fibo// return value for fibounsigned ret;unsigned ret; // to which label to goto?// to which label to goto?

} struct_s_tp;} struct_s_tp;

// recursive function for reference:// recursive function for reference:unsigned fibo( unsigned arg )unsigned fibo( unsigned arg ){ // fibo{ // fibo

calls++;calls++;if ( arg <= 1 ) {if ( arg <= 1 ) { // base case?// base case? return arg;return arg; // if so: done// if so: done}else{}else{ return fibo( arg-1 ) + fibo( arg-2 );return fibo( arg-1 ) + fibo( arg-2 );} //end if} //end if

} //end fibo} //end fibo

Page 18: 1 CS 410 Mastery in Programming Chapter 2 Recursion Herbert G. Mayer, PSU CS status 7/3/2011

18

Simulate Recursion, fibo()unsigned nr_fibo( unsigned arg )unsigned nr_fibo( unsigned arg ){ //nr_fibo{ //nr_fibo

struct_s_tp s[ MAX_STACK ];struct_s_tp s[ MAX_STACK ]; // stack can be local// stack can be local unsigned top = 0;unsigned top = 0; // initially// initially s[ top ].arg = arg;s[ top ].arg = arg; // copy arg to stack// copy arg to stack s[ top ].ret = 4;s[ top ].ret = 4; // if all fails, return// if all fails, return

l1: if ( s[ top ].arg <= 1 ) {l1: if ( s[ top ].arg <= 1 ) { s[ top ].fibo = s[ top ].arg;s[ top ].fibo = s[ top ].arg; }else{}else{ top++;top++; // ready to recurse// ready to recurse s[ top ].arg = s[ top - 1 ].arg - 1;s[ top ].arg = s[ top - 1 ].arg - 1; s[ top ].ret = 2;s[ top ].ret = 2; // to place of 1. return// to place of 1. return goto l1;goto l1; // recurse// recurse

l2:l2: top++; top++; // ready to recurse // ready to recurse againagain s[ top ].arg = s[ top - 2 ].arg - 2;s[ top ].arg = s[ top - 2 ].arg - 2; s[ top ].ret = 3;s[ top ].ret = 3; // to place of 2nd return// to place of 2nd return goto l1;goto l1; // recurse// recurse

l3:l3: // two returns simulated// two returns simulated top -= 2;top -= 2; // simulate 2 returns// simulate 2 returns s[ top ].fibo = s[ top+1 ].fibo + s[ top+2 ].fibo;s[ top ].fibo = s[ top+1 ].fibo + s[ top+2 ].fibo; } //end if} //end if if ( 2 == s[ top ].ret ) {if ( 2 == s[ top ].ret ) { // second recursive // second recursive call call goto l2;goto l2; }else if ( 3 == s[ top ].ret ) {}else if ( 3 == s[ top ].ret ) { goto l3;goto l3; } //end if} //end if

l4:l4: return s[ top ].fibo;return s[ top ].fibo; // all done// all done} //end nr_fibo } //end nr_fibo

Page 19: 1 CS 410 Mastery in Programming Chapter 2 Recursion Herbert G. Mayer, PSU CS status 7/3/2011

19

Simulate Recursion, fibo() Results r_fibo( 0) = 0, calls = 1r_fibo( 0) = 0, calls = 1 r_fibo( 1) = 1, calls = 1 r_fibo( 1) = 1, calls = 1 r_fibo( 2) = 1, calls = 3 r_fibo( 2) = 1, calls = 3

r_fibo( 3) = 2, calls = 5r_fibo( 3) = 2, calls = 5 r_fibo( 4) = 3, calls = 9 r_fibo( 4) = 3, calls = 9 . . .. . . r_fibo(22) = 17711, calls = 57313r_fibo(22) = 17711, calls = 57313 r_fibo(23) = 28657, calls = 92735 r_fibo(23) = 28657, calls = 92735 r_fibo(24) = 46368, calls = 150049 r_fibo(24) = 46368, calls = 150049 r_fibo(25) = 75025, calls = 242785 r_fibo(25) = 75025, calls = 242785 r_fibo(26) = 121393, calls = 392835 r_fibo(26) = 121393, calls = 392835 r_fibo(27) = 196418, calls = 635621 r_fibo(27) = 196418, calls = 635621 r_fibo(28) = 317811, calls = 1028457 r_fibo(28) = 317811, calls = 1028457 r_fibo(29) = 514229, calls = 1664079 r_fibo(29) = 514229, calls = 1664079

nr_fibo( 0) = 0nr_fibo( 0) = 0nr_fibo( 1) = 1nr_fibo( 1) = 1nr_fibo( 2) = 1nr_fibo( 2) = 1nr_fibo( 3) = 2nr_fibo( 3) = 2nr_fibo( 4) = 3nr_fibo( 4) = 3

. . .. . .nr_fibo(22) = 17711nr_fibo(22) = 17711nr_fibo(23) = 28657nr_fibo(23) = 28657nr_fibo(24) = 46368nr_fibo(24) = 46368nr_fibo(25) = 75025nr_fibo(25) = 75025nr_fibo(26) = 121393nr_fibo(26) = 121393nr_fibo(27) = 196418nr_fibo(27) = 196418nr_fibo(28) = 317811nr_fibo(28) = 317811nr_fibo(29) = 514229nr_fibo(29) = 514229

Page 20: 1 CS 410 Mastery in Programming Chapter 2 Recursion Herbert G. Mayer, PSU CS status 7/3/2011

20

Simulating Return of fibo()

Must the computation of the continuation place be Must the computation of the continuation place be after the if-statement? Or can we relocate it into the after the if-statement? Or can we relocate it into the Else-Clause?Else-Clause?

That would lead to a partial simulation, in which That would lead to a partial simulation, in which only the case only the case arg > 1arg > 1 continues correctly continues correctly

Yet even cases for Yet even cases for arg <= 1arg <= 1 must compute the must compute the right continuation via (unstructured) brute-force right continuation via (unstructured) brute-force gotos:gotos:

if ( 2 == s[ top ].ret ) {if ( 2 == s[ top ].ret ) { // second recursive call // second recursive call goto l2;goto l2;

}else if ( 3 == s[ top ].ret ) {}else if ( 3 == s[ top ].ret ) { goto l3;goto l3;

} //end if} //end if

Page 21: 1 CS 410 Mastery in Programming Chapter 2 Recursion Herbert G. Mayer, PSU CS status 7/3/2011

21

Simulate Recursion, fibo2()unsigned nr_fibo2( unsigned arg )unsigned nr_fibo2( unsigned arg ){ //nr_fibo2{ //nr_fibo2

struct_s_tp s[ MAX_STACK ];struct_s_tp s[ MAX_STACK ]; // stack can be local// stack can be local unsigned top = 0;unsigned top = 0; // initially// initially s[ top ].arg = arg;s[ top ].arg = arg; // copy arg to stack// copy arg to stack s[ top ].ret = 4;s[ top ].ret = 4; // if all fails, return// if all fails, return

l1: if ( s[ top ].arg <= 1 ) {l1: if ( s[ top ].arg <= 1 ) { s[ top ].fibo = s[ top ].arg;s[ top ].fibo = s[ top ].arg;

if ( 2 == s[ top ].ret ) {if ( 2 == s[ top ].ret ) { // second recursive call // second recursive call goto l2;goto l2; }else if ( 3 == s[ top ].ret ) {}else if ( 3 == s[ top ].ret ) { goto l3;goto l3; } //end if} //end if }else{}else{ top++;top++; // ready to recurse// ready to recurse s[ top ].arg = s[ top - 1 ].arg - 1;s[ top ].arg = s[ top - 1 ].arg - 1; s[ top ].ret = 2;s[ top ].ret = 2; // to place of 1. return// to place of 1. return goto l1;goto l1; // recurse// recurse

l2:l2: top++; top++; // ready to recurse again// ready to recurse again s[ top ].arg = s[ top - 2 ].arg - 2;s[ top ].arg = s[ top - 2 ].arg - 2; s[ top ].ret = 3;s[ top ].ret = 3; // to place of 2nd return// to place of 2nd return goto l1;goto l1; // recurse// recurse

l3:l3:// two returns simulated// two returns simulated top -= 2;top -= 2; // simulate 2 returns// simulate 2 returns s[ top ].fibo = s[ top+1 ].fibo + s[ top+2 ].fibo;s[ top ].fibo = s[ top+1 ].fibo + s[ top+2 ].fibo; if ( 2 == s[ top ].ret ) {if ( 2 == s[ top ].ret ) { // second recursive call // second recursive call goto l2;goto l2; }else if ( 3 == s[ top ].ret ) {}else if ( 3 == s[ top ].ret ) { goto l3;goto l3; } //end if} //end if } //end if} //end if

l4:l4: return s[ top ].fibo; return s[ top ].fibo; // all done// all done} //end nr_fibo2 } //end nr_fibo2

Page 22: 1 CS 410 Mastery in Programming Chapter 2 Recursion Herbert G. Mayer, PSU CS status 7/3/2011

22

Simulate Recursion, hanoi()void nr_hanoi( unsigned discs, char* start, char* buffer, char* target )void nr_hanoi( unsigned discs, char* start, char* buffer, char* target ){ //nr_hanoi{ //nr_hanoi

struct_h_type s[ MAX_STACK ];struct_h_type s[ MAX_STACK ];unsigned top = 0;unsigned top = 0;s[ top ].discs = discs;s[ top ].discs = discs;s[ top ].start = start;s[ top ].start = start;s[ top ].buffer = buffer;s[ top ].buffer = buffer;s[ top ].target = target;s[ top ].target = target;s[ top ].ret = 4;s[ top ].ret = 4;

l1:l1:if ( s[ top ].discs > 0 ) {if ( s[ top ].discs > 0 ) {top++;top++;s[ top ].discs = s[ top-1 ].discs - 1;s[ top ].discs = s[ top-1 ].discs - 1;s[ top ].start = s[ top-1 ].start;s[ top ].start = s[ top-1 ].start;s[ top ].buffer= s[ top-1 ].target;s[ top ].buffer= s[ top-1 ].target;s[ top ].target= s[ top-1 ].buffer;s[ top ].target= s[ top-1 ].buffer;s[ top ].ret = 2;s[ top ].ret = 2;goto l1;goto l1;

l2:l2:printf( "nr move disc %1u from %s to %s\n",printf( "nr move disc %1u from %s to %s\n",s[ top ].discs, s[ top ].start, s[ top ].target );s[ top ].discs, s[ top ].start, s[ top ].target );

top++;top++; s[ top ].discs = s[ top-1 ].discs - 1;s[ top ].discs = s[ top-1 ].discs - 1; s[ top ].start = s[ top-1 ].buffer;s[ top ].start = s[ top-1 ].buffer; s[ top ].buffer= s[ top-1 ].start;s[ top ].buffer= s[ top-1 ].start; s[ top ].target= s[ top-1 ].target;s[ top ].target= s[ top-1 ].target; s[ top ].ret = 3;s[ top ].ret = 3; goto l1;goto l1;} //end if} //end if

l3:l3:if ( 2 == s[ top ].ret ) {if ( 2 == s[ top ].ret ) { top--;top--; goto l2;goto l2;}else if ( 3 == s[ top ].ret ) {}else if ( 3 == s[ top ].ret ) { top--;top--; goto l3;goto l3;} //end if} //end if

} //end nr_hanoi} //end nr_hanoi

Page 23: 1 CS 410 Mastery in Programming Chapter 2 Recursion Herbert G. Mayer, PSU CS status 7/3/2011

23

References1.1. Douglas R. Hofstader, “Gödel, Escher, Bach: an Douglas R. Hofstader, “Gödel, Escher, Bach: an

eternal golden braid”, Basic Books, 1999, ISBN eternal golden braid”, Basic Books, 1999, ISBN 04650265670465026567

2.2. Ackermann functiona at NIST: Ackermann functiona at NIST: http://xlinux.nist.gov/dads/HTML/ackermann.htmlhttp://xlinux.nist.gov/dads/HTML/ackermann.html

3.3. Herbert G Mayer: “Advanced C Programming on the Herbert G Mayer: “Advanced C Programming on the IBM PC”, 1989, Windcrest, ISBN 0-8306-9163-4IBM PC”, 1989, Windcrest, ISBN 0-8306-9163-4

4.4. Non-recursive solution to Towers of Hanoi: Non-recursive solution to Towers of Hanoi: http://portal.acm.org/citation.cfm?id=948602http://portal.acm.org/citation.cfm?id=948602