1 cs 162 introduction to computer science chapter 10 c++ simulation of recursion herbert g. mayer,...

41
1 CS 162 Introduction to Computer Science Chapter 10 C++ Simulation of Recursion Herbert G. Mayer, PSU Status 11/17/2014

Upload: julian-henry

Post on 23-Dec-2015

223 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: 1 CS 162 Introduction to Computer Science Chapter 10 C++ Simulation of Recursion Herbert G. Mayer, PSU Status 11/17/2014

1

CS 162Introduction to Computer Science

Chapter 10C++ Simulation of Recursion

Herbert G. Mayer, PSUStatus 11/17/2014

Page 2: 1 CS 162 Introduction to Computer Science Chapter 10 C++ Simulation of Recursion Herbert G. Mayer, PSU Status 11/17/2014

2

Syllabus Definition of Recursive Algorithm

Recursion vs. Iteration

Fact() and Fibo(), Recursive and Iterative

Q-Sequence

Ackermann Function

Stack Data Structure

Simulate Recursion via Iteration

References

Page 3: 1 CS 162 Introduction to Computer Science Chapter 10 C++ Simulation of Recursion Herbert G. Mayer, PSU Status 11/17/2014

3

Definition of Recursive AlgorithmAn algorithms is recursive, if it is partly defined by simpler versions of itself [1]

A recursive program is the implementation of a recursive algorithm What is the problem for a programmer, using a language that is non-recursive (e.g.

standard Fortran) if the algorithm to be implemented is recursive? --See later!

What then are the other parts of a recursive algorithm, aside from the partly? Correct recursive algorithm requires a starting point, formally known as “base case” Base case could be multiple steps

Simpler version means: the algorithm cannot use the original call. For example, if the original call was a(n), the recursive call cannot also be a(n), but perhaps a(n-1)

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

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

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 162 Introduction to Computer Science Chapter 10 C++ Simulation of Recursion Herbert G. Mayer, PSU Status 11/17/2014

4

Recursion vs. Iteration• Iteration is expressed in programming languages by

loops; e.g. for-, while-, do-, or repeat loops

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

• Recursion can replace iterative steps; yet for some people this seems counter-intuitive

• Neophytes are sometimes unused to recursion; yet recursion can be as intuitive as simple iteration

Page 5: 1 CS 162 Introduction to Computer Science Chapter 10 C++ Simulation of Recursion Herbert G. Mayer, PSU Status 11/17/2014

5

Fact() and Fibo(), Recursive + Iterative We’ll show both solutions for the factorial and the

fibonacci functions Factorial: fact1() iterative, fact2() recursive

Fibonacci: fibo1() iterative, fibo2() recursive

Sometimes the recursive algorithm is easier to see + understand, if the problem is inherently recursive

Later we discuss both with recursion simulated, not at CCUT CS 162

Fibonacci was Italian mathematician in Pisa, 1170 – c. 1250; introduced Hindu-Arabic numeral system to Europe

Also show the famous Towers of Hanoi

Page 6: 1 CS 162 Introduction to Computer Science Chapter 10 C++ Simulation of Recursion Herbert G. Mayer, PSU Status 11/17/2014

6

Fact() and Fibo(), Recursive + Iterative

Factorial(n) is the product of the first n unsigned numbers, with factorial(0) defined as = 1

Fibonacci(n) is defined as 0 and 1 for arguments indexed 0, and 1. For all other n the result is the sum of the previous 2 Fibonacci numbers, i.e. Fibonacci(n) = Fibonacci(n-1) + Fibonacci(n-2)

Page 7: 1 CS 162 Introduction to Computer Science Chapter 10 C++ Simulation of Recursion Herbert G. Mayer, PSU Status 11/17/2014

7

Fact(), Recursive and Iterative#include <iostream.h>

unsigned fact1( unsigned arg ) // iterative{ // fact1

unsigned int result = 1;for ( int i = 1; i <= arg; i++ ) {

result *= i;} //end forreturn result;

} //end fact1

unsigned fact2( unsigned arg ) // recursive{ // fact2

if ( arg < 2 ) {return 1;

}else{return arg * fact2( arg-1 );

} //end if} //end fact2

Page 8: 1 CS 162 Introduction to Computer Science Chapter 10 C++ Simulation of Recursion Herbert G. Mayer, PSU Status 11/17/2014

8

Fact(), Recursive and Iterativeint main( void ){ // main

for ( int i = 0; i < 10; i++ ) {cout << "fact1(" << i << ") = " << fact1( i )

<< endl<< "fact2(" << i << ") = " <<

fact2( i ) << endl;} //end for

return 0;} //end main

fact1(0) = 1fact2(0) = 1fact1(1) = 1fact2(1) = 1fact1(2) = 2fact2(2) = 2. . .fact1(7) = 5040fact2(7) = 5040fact1(8) = 40320fact2(8) = 40320fact1(9) = 362880fact2(9) = 362880

Page 9: 1 CS 162 Introduction to Computer Science Chapter 10 C++ Simulation of Recursion Herbert G. Mayer, PSU Status 11/17/2014

9

Fibo(), Recursive and Iterative#include <iostream.h>unsigned fibo1( unsigned arg ) // iterative{ // fibo1

unsigned fm2 = 0;unsigned fm1 = 1;unsigned fm0 = 1;for ( int i = 1; i <= arg; i++ ) {

fm2 = fm1;fm1 = fm0;fm0 = fm1 + fm2;

} //end forreturn fm2;

} //end fibo1

unsigned fibo2( unsigned arg ) // recursive{ // fibo2

if ( arg < 2 ) {return arg;

}else{return fibo2( arg-1 ) + fibo2( arg-2 );

} //end if} //end fibo2

Page 10: 1 CS 162 Introduction to Computer Science Chapter 10 C++ Simulation of Recursion Herbert G. Mayer, PSU Status 11/17/2014

10

Fibo(), Recursive and Iterativeint main( void ){ // main

for ( int i = 0; i < 10; i++ ) {cout << "fibo1(" << i << ") = " << fibo1( i ) << endl

<< "fibo2(" << i << ") = " << fibo2( i ) << endl;} //end forreturn 0;

} //end main

fibo1(0) = 0fibo2(0) = 0fibo1(1) = 1fibo2(1) = 1fibo1(2) = 1fibo2(2) = 1fibo1(3) = 2fibo2(3) = 2fibo1(4) = 3fibo2(4) = 3. . .fibo1(9) = 34fibo2(9) = 34

Page 11: 1 CS 162 Introduction to Computer Science Chapter 10 C++ Simulation of Recursion Herbert G. Mayer, PSU Status 11/17/2014

11

Replace Iteration via Recursion• What is the problem, if algorithm to be programmed

is recursive, but language does not allow recursion?1. Rewrite the algorithm

2. Or simulate recursion <- not discussed at CCUT!

• Here we do the opposite: Use recursion to simulate all mathematical dyadic operations + - / * etc.

• Using only functions, called recursively

• Plus arithmetic increment/decrement operators ++ -- and unary minus –

• And conventional relational operators > >= != etc.

• All other operators are dis-allowed, i.e. cannot use + - * / % ** etc.

Page 12: 1 CS 162 Introduction to Computer Science Chapter 10 C++ Simulation of Recursion Herbert G. Mayer, PSU Status 11/17/2014

12

Recursion vs. Iteration: add()

// return a + b without + operation!int add( int a, int b ){ // addif ( 0 == b ) {

return a;}else if ( b < 0 ) {

return add( --a, ++b );}else{

return add( ++a, --b );} //end if

} //end add

Page 13: 1 CS 162 Introduction to Computer Science Chapter 10 C++ Simulation of Recursion Herbert G. Mayer, PSU Status 11/17/2014

13

Recursion vs. Iteration: sub()

// return a – b; no dyadic – operationint sub( int a, int b ){ // subreturn add( a, -b );

} //end sub

Page 14: 1 CS 162 Introduction to Computer Science Chapter 10 C++ Simulation of Recursion Herbert G. Mayer, PSU Status 11/17/2014

14

Recursion vs. Iteration: mult()// return a * b, no * but add()int mult( int a, int b ){ // multif ( 0 == b ) {

return 0;}else if ( 1 == b ) {

return a;}else if ( b < 0 ) {

return -mult( a, -b );}else{

// b > 0return add( a, mult( a, --b

) );} //end if

} //end mult

Page 15: 1 CS 162 Introduction to Computer Science Chapter 10 C++ Simulation of Recursion Herbert G. Mayer, PSU Status 11/17/2014

15

Recursion vs. Iteration: expo()// return a ** b, no ** op in C++; requires mult( int, int )int expo( int a, int b ){ // expo if ( 0 == a ) { if ( 0 == b ) { printf( ”undefined value0^0\n" ); }else if ( b < 0 ) { printf( “0 to <0 power is undefined\n" );

} //end if return 0;

}else if ( 0 == b ) { return 1; }else if ( 1 == a ) { return 1; }else if ( -1 == a ) { return b % 2 ? -1 : 1; }else if ( b < 0 ) { return 0; }else{ return mult( expo( a, --b ), a ); } //end if} //end expo

Page 16: 1 CS 162 Introduction to Computer Science Chapter 10 C++ Simulation of Recursion Herbert G. Mayer, PSU Status 11/17/2014

16

Q-Sequence, DefinitionQ-Sequence defined by Douglas Hofstadter in [1] as a function q( n ) for

positive integers n > 0

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

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

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

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

By contract, the function results of fibonacci( n ) are monotonically increasing with increasing argument

Results of q( n ) are non-monotonic!

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

Page 17: 1 CS 162 Introduction to Computer Science Chapter 10 C++ Simulation of Recursion Herbert G. Mayer, PSU Status 11/17/2014

17

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

int q( int arg ){ // q

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

} // end q

void main(){ // main

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

} // end main

Page 18: 1 CS 162 Introduction to Computer Science Chapter 10 C++ Simulation of Recursion Herbert G. Mayer, PSU Status 11/17/2014

18

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

. . .

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

. . . Will never reach Q(100) in your life time

Page 19: 1 CS 162 Introduction to Computer Science Chapter 10 C++ Simulation of Recursion Herbert G. Mayer, PSU Status 11/17/2014

19

Ackermann Definition

Ackermann a( m, n ) is defined as a function of two non-negative (i.e. unsigned in C++) integers m and n

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

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

Ackermann complexity grows awfully fast; e.g. a(4,2) is an integer number with 19,729 decimal digits; greater than the national US debt!

Page 20: 1 CS 162 Introduction to Computer Science Chapter 10 C++ Simulation of Recursion Herbert G. Mayer, PSU Status 11/17/2014

20

Ackermann Definition

Students, code now in C++, volunteers shows result on white-board:

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

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

Page 21: 1 CS 162 Introduction to Computer Science Chapter 10 C++ Simulation of Recursion Herbert G. Mayer, PSU Status 11/17/2014

21

Ackermann Coded in C++

unsigned a( unsigned m, unsigned n ){ // a

calls++;// global unsigned

if ( 0 == m ) { // note operand order return n + 1; // first base case}else if ( 0 == n ) { // m > 0

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

// m > 0, n > 0 return a( m-1, a( m, n-1 ) ); // recurse!

} // end if} // end q

void main(){ // main

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

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

%12u\n", i, j, a( i, j ), calls );

} // end for} // end forreturn 0;

} // end main

Page 22: 1 CS 162 Introduction to Computer Science Chapter 10 C++ Simulation of Recursion Herbert G. Mayer, PSU Status 11/17/2014

22

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

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

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

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

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

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

Page 23: 1 CS 162 Introduction to Computer Science Chapter 10 C++ Simulation of Recursion Herbert G. Mayer, PSU Status 11/17/2014

23

Stack Data Structure High-level language functions call each other in a

nested fashion, recursively, even indirectly recursively

And return in strictly the reverse order (LIFO), but with any number of further calls in between

Stack is the natural data structure to track callée return information

Languages also allow local data per function call, of which formal parameters are just one variation

Natural to have locals also live and die on the run time stack, synchronized with call-return information

Possible but wasteful to have a separate stack for automatic locals: conclusion to have unified stack

Page 24: 1 CS 162 Introduction to Computer Science Chapter 10 C++ Simulation of Recursion Herbert G. Mayer, PSU Status 11/17/2014

24

Other temps

0 or more locals

Field 1: Function return value

Caller pushes formals

0..32 registers saved

Field 2: return address

Field 3: dynamic link

Field 4: static link

sp

bp

hp

Stack Marker

Stack Frame

Stack Frame of callee

Stack growsdownwardsStack growsdownward

Page 25: 1 CS 162 Introduction to Computer Science Chapter 10 C++ Simulation of Recursion Herbert G. Mayer, PSU Status 11/17/2014

25

Stack Data Structure Stack is natural data structure for recursive call:

1.) Before call: provide (push) all actual parameters During the call, these are the formal parameters 2.) Then execute call, provide the return address on stack Provide space on stack for return value if needed (function) And push bp register, pointing to the frame of caller: known

as dynamic link 3.) Before executing callée code: allocate locals on stack And allocate temps, e.g. copies of all regs to be used, save

them and later restore before return

Thus stack grows by 3 physical + logical sections:1. Formal parameters, some of them just addresses for &

2. Stack Marker, AKA Activation Record: RA, RV, Dynamic Link

3. Locals + temps+ saved regs

Page 26: 1 CS 162 Introduction to Computer Science Chapter 10 C++ Simulation of Recursion Herbert G. Mayer, PSU Status 11/17/2014

26

Stack Data Structure Stack is addressed by 2 HW resources, typically registers bp

and sp (AKA top) It is computable to have a single register address stack via

current frame, since the compiler “knows” at each place, by how much stack must have grown

Actually so done by Greenhills compilers in 1990s for register-starved Intel architecture

Base Pointer register bp points to some defined place of stack marker, typically to dynamic link

The top of stack register sp points to the dynamically changing, momentary top of stack –dynamic = during the call

The bp stays invariant during the call; changes only at further calls and at any returns –static = during the call

The sp changes with each call preparation, each temp pushed on top, each intermediate result, etc.

Page 27: 1 CS 162 Introduction to Computer Science Chapter 10 C++ Simulation of Recursion Herbert G. Mayer, PSU Status 11/17/2014

27

Simulate Recursion via Iteration• Important for master programmer to understand RT-

stack and recursion!• What to do, if you implement a recursive algorithm

using a language that does not support recursion?• Replace recursive by a non-recursive algorithm!• Or simulate recursion via non-recursive methods• After all, a computer chip has no notion of recursion; it

is a sequential machine that “simulates recursion” via non-recursive methods; the compiler plus run-time system perform this transformation!

• Done so at local industry in the past: FPS used Fortran!! to implement System SW and compilers

• Here are the actual steps of simulating recursion via iteration; must use language with Goto –terrible sin

Page 28: 1 CS 162 Introduction to Computer Science Chapter 10 C++ Simulation of Recursion Herbert G. Mayer, PSU Status 11/17/2014

28

Steps of Simulating Recursion consider directly-recursive calls of simulated function:1. Define data structure struct stack_tp, to hold params, locals, etc.2. Define explicit stack with top of stack (top) index, initially top=0;

like a real stack identified by sp, may overflow, so include code to check; stack[ top ] holds parameters, function return value, return location (labels after a recursive call), and automatics

3. Define labels for each point of recursive call, more precisely at each point after the call; number these points of return, e.g. l1, l2, l3, l4 etc. There shall be branches=gotos to these points of return

4. At each point of recursive call: Increment : i.e. top++, like HW recursion that grows + shrinks sp Manually move parameters for “this call” onto stack; e.g. assign:

stack[ top ].arg1 = actual1; stack[ top ].arg2 = actual2 . . Store the place of return:

stack[ top ].ret = 1, or 2, or 3 alluding to l1, l2, l3 . . . Initialize local, automatic objects: stack[ top ].local1 = value1 . . . Jump (Goto, the terrible sin!) to function head, not including initializing code

Page 29: 1 CS 162 Introduction to Computer Science Chapter 10 C++ Simulation of Recursion Herbert G. Mayer, PSU Status 11/17/2014

29

Steps of Simulating Recursion4. Point of return: In simple cases, all explicitly coded returns

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

branch to simulate return (via goto) to continue execution; e.g.:

if ( stack[ top+1 ].ret == xyz ) goto label_xyz;

And if no other branch is open, then fall through to the end For void functions this is a literal fall-through For true functions, the return value has to be computed before

the fall-through, e.g.:return stack[ top ].return_val; // top is that of caller!

5. For nested recursive calls or several recursive calls in a row or both: “be creative” ; see an example later; apply these steps with meticulous precision

Page 30: 1 CS 162 Introduction to Computer Science Chapter 10 C++ Simulation of Recursion Herbert G. Mayer, PSU Status 11/17/2014

30

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

32bits

unsigned calls = 0; // track # of calls

typedef struct s_tp {unsigned arg; // for formal parametersunsigned fact; // function return valueunsigned ret; // code address after call, return!

} struct_s_tp;

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

calls++; // gotta be globalif ( 0 == arg ) { // why strange order? return 1;}else{ return fact( arg - 1 ) * arg;} // end if// there should be an assertion here!

} // end fact

Page 31: 1 CS 162 Introduction to Computer Science Chapter 10 C++ Simulation of Recursion Herbert G. Mayer, PSU Status 11/17/2014

31

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

struct_s_tp s[ MAX_STACK ]; // simulate RT stack!unsigned top = 0; // simulate sp registers[ top ].arg = arg; // this call’s arguments[ top ].ret = 3; // 3 alludes to label l3

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

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

l3:return s[ top ].fact;

} // end nrfact

Page 32: 1 CS 162 Introduction to Computer Science Chapter 10 C++ Simulation of Recursion Herbert G. Mayer, PSU Status 11/17/2014

32

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

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

Page 33: 1 CS 162 Introduction to Computer Science Chapter 10 C++ Simulation of Recursion Herbert G. Mayer, PSU Status 11/17/2014

33

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

computable!

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

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

} struct_s_tp;

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

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

} // end fibo

Page 34: 1 CS 162 Introduction to Computer Science Chapter 10 C++ Simulation of Recursion Herbert G. Mayer, PSU Status 11/17/2014

34

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

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

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

l2: top++;// ready to recurse again

s[ top ].arg = s[ top - 2 ].arg - 2; s[ top ].ret = 3; // to place of 2nd return goto l1; // recurse!

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

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

Page 35: 1 CS 162 Introduction to Computer Science Chapter 10 C++ Simulation of Recursion Herbert G. Mayer, PSU Status 11/17/2014

35

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

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

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

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

Page 36: 1 CS 162 Introduction to Computer Science Chapter 10 C++ Simulation of Recursion Herbert G. Mayer, PSU Status 11/17/2014

36

Simulating Return of fibo()

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

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

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

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

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

} // end if

Page 37: 1 CS 162 Introduction to Computer Science Chapter 10 C++ Simulation of Recursion Herbert G. Mayer, PSU Status 11/17/2014

37

Towers of hanoi() The game of the “Towers of Hanoi” is a game to

move a stack of n discs, while obeying certain rules

All n discs are of different sizes, residing on top of one another, a smaller disc always over a larger

The goal is to move the whole tower from start, to the goal position, using one additional buffer location

But only moving 1 single disc at a time

And never placing a larger disc on top of a smaller

During various times, any disc may be placed on the start position, the goal, or the buffer

Page 38: 1 CS 162 Introduction to Computer Science Chapter 10 C++ Simulation of Recursion Herbert G. Mayer, PSU Status 11/17/2014

38

Towers of hanoi(), Recursive#include <iostream.h>#define MAX … some small integer < 32

void hanoi( int discs, char* start, char* goal, char* buff ){ // hanoi

if ( discs > 0 ){hanoi( discs-1, start, buff, goal );cout << "move disc " << discs << " from " << start

<< " to “ << goal << endl;hanoi( discs-1, buff, goal, start );

} // end if} // end hanoi

int main(){ // main

for ( int discs = 1; discs <= MAX; discs++ ) {cout << ” hanoi for " << discs << " discs" << endl;hanoi( discs, "start", "goal ", "buff " );cout << endl;

} // end for return 0;

} // end main

Page 39: 1 CS 162 Introduction to Computer Science Chapter 10 C++ Simulation of Recursion Herbert G. Mayer, PSU Status 11/17/2014

39

Towers of hanoi(), Recursivemove disc 1 from start to goal < For 1 disc

move disc 1 from start to buff < For 2 discs move disc 2 from start to goal move disc 1 from buff to goal

move disc 1 from start to goal < For 3 discs move disc 2 from start to buff move disc 1 from goal to buff move disc 3 from start to goal move disc 1 from buff to startmove disc 2 from buff to goal move disc 1 from start to goal

move disc 1 from start to buff < For 4 discs move disc 2 from start to goal move disc 1 from buff to goal move disc 3 from start to buff move disc 1 from goal to startmove disc 2 from goal to buff move disc 1 from start to buff move disc 4 from start to goal move disc 1 from buff to goal move disc 2 from buff to startmove disc 1 from goal to startmove disc 3 from buff to goal move disc 1 from start to buff move disc 2 from start to goal move disc 1 from buff to goal

Page 40: 1 CS 162 Introduction to Computer Science Chapter 10 C++ Simulation of Recursion Herbert G. Mayer, PSU Status 11/17/2014

40

Simulate Recursion, hanoi()void nr_hanoi( unsigned discs, char* start, char* goal, char* buff ){ // nr_hanoi

struct_h_type s[ MAX_STACK ]; unsigned top = 0;s[ top ].discs = discs;s[ top ].start = start;s[ top ].buff = buff;s[ top ].goal = goal;s[ top ].ret = 4;

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

l2:cout << "nr move disc “ << s[ top ].discs << “ from “ << s[ top ].start << “ to “ << s[ top ].goal << endl;

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

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

} // end nr_hanoi

Page 41: 1 CS 162 Introduction to Computer Science Chapter 10 C++ Simulation of Recursion Herbert G. Mayer, PSU Status 11/17/2014

41

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

eternal golden braid”, Basic Books, 1999, ISBN 0465026567; came out in 1979

2. Ackermann function at NIST: http://xlinux.nist.gov/dads/HTML/ackermann.html

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

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

5. Herbert G Mayer, Don Perkins, SIGLAN Notices, 1984, non-recursive Towers of Hanoi Solution: http://dl.acm.org/citation.cfm?id=948573