CS 320 Principles of Programming Languages

Slides:



Advertisements
Similar presentations
1 Lecture 3: MIPS Instruction Set Today’s topic:  More MIPS instructions  Procedure call/return Reminder: Assignment 1 is on the class web-page (due.
Advertisements

Intermediate Code Generation
The University of Adelaide, School of Computer Science
COMP3221 lec16-function-II.1 Saeid Nooshabadi COMP 3221 Microprocessors and Embedded Systems Lectures 16 : Functions in C/ Assembly - II
1 Lecture 4: Procedure Calls Today’s topics:  Procedure calls  Large constants  The compilation process Reminder: Assignment 1 is due on Thursday.
Computer Architecture CSCE 350
CPS3340 COMPUTER ARCHITECTURE Fall Semester, /17/2013 Lecture 12: Procedures Instructor: Ashraf Yaseen DEPARTMENT OF MATH & COMPUTER SCIENCE CENTRAL.
Ch. 8 Functions.
Procedures II (1) Fall 2005 Lecture 07: Procedure Calls (Part 2)
Apr. 12, 2000Systems Architecture I1 Systems Architecture I (CS ) Lecture 6: Branching and Procedures in MIPS* Jeremy R. Johnson Wed. Apr. 12, 2000.
The University of Adelaide, School of Computer Science
CSCI-365 Computer Organization Lecture Note: Some slides and/or pictures in the following are adapted from: Computer Organization and Design, Patterson.
ECE 103 Engineering Programming Chapter 11 One Minute Synopsis Herbert G. Mayer, PSU CS Status 7/1/2014.
1 Storage Registers vs. memory Access to registers is much faster than access to memory Goal: store as much data as possible in registers Limitations/considerations:
CS 536 Spring Code generation I Lecture 20.
Lecture 6: Procedures (cont.). Procedures Review Called with a jal instruction, returns with a jr $ra Accepts up to 4 arguments in $a0, $a1, $a2 and $a3.
More on FunctionsCS-2301 B-term More on Functions CS-2301, System Programming for Non-majors (Slides include materials from The C Programming Language,
1 CS 410 Mastery in Programming Chapter 2 Recursion Herbert G. Mayer, PSU CS status 7/3/2011.
Recursion and Function Implementation CS-2301 D-term Recursion and Implementation of Functions CS-2301 System Programming C-term 2009 (Slides include.
1 CS 162 Introduction to Computer Science Chapter 10 C++ Simulation of Recursion Herbert G. Mayer, PSU Status 11/17/2014.
Recursion and Implementation of Functions
CS-2710 Dr. Mark L. Hornick 1 Defining and calling procedures (subroutines) in assembly And using the Stack.
1 CS 162 Introduction to Computer Science Chapter 4 Function Calls Herbert G. Mayer, PSU Status 11/9/2014.
IT253: Computer Organization Lecture 4: Instruction Set Architecture Tonga Institute of Higher Education.
13/02/2009CA&O Lecture 04 by Engr. Umbreen Sabir Computer Architecture & Organization Instructions: Language of Computer Engr. Umbreen Sabir Computer Engineering.
1 CS 410 / 510 Mastery in Programming Chapter 2 Recursion Herbert G. Mayer, PSU CS Status 7/6/2013 With improvements suggested by: Gaby Haddock, summer.
Compiler Construction
Slides revised 3/25/2014 by Patrick Kelley. 2 Procedures Higher Level languages have adopted a standard Referred to as C-style calling Uses the stack.
Recursion. What is recursion? Rules of recursion Mathematical induction The Fibonacci sequence Summary Outline.
COP4020 Programming Languages Subroutines and Parameter Passing Prof. Xin Yuan.
Procedure Basics Computer Organization I 1 October 2009 © McQuain, Feng & Ribbens Procedure Support From previous study of high-level languages,
ITCS 3181 Logic and Computer Systems 2015 B. Wilkinson Slides4-2.ppt Modification date: March 23, Procedures Essential ingredient of high level.
1 CS 163 Data Structures Chapter 6 Function Calls and Recursion Herbert G. Mayer, PSU Status 6/1/2015.
Chapter 2 — Instructions: Language of the Computer — 1 Conditional Operations Branch to a labeled instruction if a condition is true – Otherwise, continue.
RecursionCIS 1057 Fall Recursion CIS 1057 Computer Programming in C Fall 2013 (Many slides based on/borrowed from Professor Hugh C. Lauer. Slides.
ECE 103 Engineering Programming Chapter 30 C Functions Herbert G. Mayer, PSU CS Status 8/9/2014 Initial content copied verbatim from ECE 103 material developed.
LECTURE 19 Subroutines and Parameter Passing. ABSTRACTION Recall: Abstraction is the process by which we can hide larger or more complex code fragments.
Recursion.
Implementing Subprograms
Computer Architecture & Operations I
Lecture 7 Macro Review Stack Frames
Chapter 5 Microprocessor Runtime Stack
CS 201 Computer Systems Programming Chapter 6 “Recursion”
Data Structures and Algorithms
Compilers Principles, Techniques, & Tools Taught by Jing Zhang
© Craig Zilles (adapted from slides by Howard Huang)
More on Recursive Methods
Run-time organization
Introduction to Compilers Tim Teitelbaum
Procedures (Functions)
Recursive Thinking Chapter 9 introduces the technique of recursive programming. As you have seen, recursive programming involves spotting smaller occurrences.
6.001 SICP Stacks and recursion
Recursive Thinking Chapter 9 introduces the technique of recursive programming. As you have seen, recursive programming involves spotting smaller occurrences.
Chapter 9 :: Subroutines and Control Abstraction
Implementing Subprograms
Chap. 8 :: Subroutines and Control Abstraction
Chap. 8 :: Subroutines and Control Abstraction
Stacks & Recursion.
CS 320 Principles of Programming Languages
The University of Adelaide, School of Computer Science
Recursion and Implementation of Functions
UNIT V Run Time Environments.
Program and memory layout
Yan Shi CS/SE 2630 Lecture Notes
Computer Architecture
10/6: Lecture Topics C Brainteaser More on Procedure Call
Where is all the knowledge we lost with information? T. S. Eliot
© Craig Zilles (adapted from slides by Howard Huang)
Implementing Subprograms
Presentation transcript:

CS 320 Principles of Programming Languages Recursive Ackerman Dr. Herbert G. Mayer, PSU Status 10/7/2017

Syllabus Definition of Recursive Algorithm Recursion vs. Iteration Q-Sequence Ackermann Function Stack Data Structure Simulate Recursion via Iteration References

Definition of Recursive Algorithm An 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 key 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? Correct recursive algorithm requires a starting point, formally known as “base case” Base case could be multiple steps Recursive algorithm a() uses a base case as starting point for computation, plus the actual function body, including some recursive use of a() 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: 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 )

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 

Replace Iteration via Recursion Using only functions, called recursively Plus arithmetic increment/decrement operators ++ -- and unary minus – And conventional relational operators > >= != etc. All other operators are dis-allowed in this experiment, i.e. no + - * / % ** etc.

Recursion vs. Iteration: add() // return a + b without + operation! int add( int a, int b ) { // add if ( 0 == b ) { return a; }else if ( b < 0 ) { return add( --a, ++b ); }else{ return add( ++a, --b ); } //end if } //end add

Recursion vs. Iteration: sub() // return a – b; no dyadic – operation int sub( int a, int b ) { // sub return add( a, -b ); } //end sub

Recursion vs. Iteration: mult() // return a * b, no * but add() int mult( int a, int b ) { // mult if ( 0 == b ) { return 0; }else if ( 1 == b ) { return a; }else if ( b < 0 ) { return -mult( a, -b ); }else{ // b > 0 return add( a, mult( a, --b ) ); } //end if } //end mult

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 ) { }else if ( -1 == a ) { return b % 2 ? -1 : 1; }else{ return mult( expo( a, --b ), a ); } //end expo

Q-Sequence, Definition Q-Sequence defined by Douglas Hofstadter in [1] as a function q( n ) for positive integers n > 0 Base case n = 1: q(1) = 1 Base 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

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 call if ( 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

Q-Sequence Results Q( 1) = 1, #calls = 1 Q( 2) = 1, #calls = 1 Q( 3) = 2, #calls = 5 Q( 4) = 3, #calls = 13 Q( 5) = 3, #calls = 25 Q( 6) = 4, #calls = 49 Q( 7) = 5, #calls = 93 Q( 8) = 5, #calls = 161 Q( 9) = 6, #calls = 281 Q(10) = 6, #calls = 481 Q(11) = 6, #calls = 813 . . . Q(26) = 14, #calls = 1341433 Q(27) = 16, #calls = 2174493 Q(28) = 16, #calls = 3521137 Q(29) = 16, #calls = 5700281 Q(30) = 16, #calls = 9229053 Q(31) = 20, #calls = 14941993 Q(32) = 17, #calls = 24182797 Q(33) = 17, #calls = 39137473 Q(34) = 20, #calls = 63354153 Q(35) = 21, #calls = 102525697 Q(36) = 19, #calls = 165896537 Q(37) = 20, #calls = 268460333 Q(38) = 22, #calls = 434429737 Q(39) = 21, #calls = 702952137 Q(40) = 22, #calls = 1137454741 . . . Will never reach Q(100) in your life time 

Ackermann Definition Ackermann a( m, n ) is defined as a function of two non-negative integers m and n Base case 1: a( 0, n ) = n + 1 Base case 2: a( m, 0 ) = a( m - 1, 1 ) Recursive definition of a( m, n ), m, n > 0 a( 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!

Ackermann Definition Students, code now in C++, volunteers show result on white-board: Base case 1: a( 0, n ) = n + 1 Base case 2: a( m, 0 ) = a( m - 1, 1 ) Recursive definition of a( m, n ), m, n > 0 a( m, n ) = a( m - 1, a( m, n - 1 ) )

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 main

Ackermann Results For m = 0 a(0,0) = 1, calls = 1 . . . a(1,7) = 9, calls = 16 For m = 2 a(2,0) = 3, calls = 5 a(2,1) = 5, calls = 14 a(2,2) = 7, calls = 27 a(2,3) = 9, calls = 44 a(2,4) = 11, calls = 65 a(2,5) = 13, calls = 90 a(2,6) = 15, calls = 119 a(2,7) = 17, calls = 152 For m = 3 a(3,0) = 5, calls = 15 a(3,1) = 13, calls = 106 a(3,2) = 29, calls = 541 a(3,3) = 61, calls = 2432 a(3,4) = 125, calls = 10307 a(3,5) = 253, calls = 42438 a(3,6) = 509, calls = 172233 a(3,7) = 1021, calls = 693964 For m = 4 a(4,0) = 13, calls = 107 don’t even dream about computing a(4,2)  or higher!

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

Stack grows downward bp Stack grows downwards Stack Marker Stack Frame 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 grows downwards Stack grows downward

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: Formal parameters, some of them just addresses for & Stack Marker, AKA Activation Record: RA, RV, Dynamic Link Locals + temps+ saved regs

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.

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 

Steps of Simulating Recursion consider directly-recursive calls of simulated function: Define data structure struct stack_tp, to hold params, locals, etc. 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 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 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

Steps of Simulating Recursion 4. 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

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 parameters unsigned fact; // function return value unsigned ret; // code address after call, return! } struct_s_tp; // first the recursive fact() function for reference // includes tracking # of calls unsigned fact( unsigned arg ) { // fact calls++; // gotta be global if ( 0 == arg ) { // why strange order? return 1; }else{ return fact( arg - 1 ) * arg; } // end if // there should be an assertion here! } // end fact

Simulate Recursion, fact() unsigned nrfact( unsigned arg ) { // nrfact struct_s_tp s[ MAX_STACK ]; // simulate RT stack! unsigned top = 0; // simulate sp register s[ top ].arg = arg; // this call’s argument s[ 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 if if ( s[ top ].ret == 2 ) { // test, where to branch to goto l2; // unstructured goto into if l3: return s[ top ].fact; } // end nrfact

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) = 1 nr_fact( 1) = 1 nr_fact( 2) = 2 nr_fact( 3) = 6 nr_fact( 4) = 24 nr_fact( 5) = 120 nr_fact( 6) = 720 nr_fact( 7) = 5040 nr_fact( 8) = 40320 nr_fact( 9) = 362880 nr_fact(10) = 3628800 nr_fact(11) = 39916800 nr_fact(12) = 479001600 nr_fact(13) = 1932053504

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 stack unsigned arg; // copy of fibo’s arg unsigned fibo; // return value for fibo unsigned 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

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 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; l4: return s[ top ].fibo; // all done } // end nr_fibo

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) = 0 nr_fibo( 1) = 1 nr_fibo( 2) = 1 nr_fibo( 3) = 2 nr_fibo( 4) = 3 . . . nr_fibo(22) = 17711 nr_fibo(23) = 28657 nr_fibo(24) = 46368 nr_fibo(25) = 75025 nr_fibo(26) = 121393 nr_fibo(27) = 196418 nr_fibo(28) = 317811 nr_fibo(29) = 514229

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

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

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

Towers of hanoi(), Recursive move 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 start move 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 3 from start to buff move disc 1 from goal to start move disc 2 from goal to buff move disc 1 from start to buff move disc 4 from start to goal move disc 2 from buff to start move disc 3 from buff to goal

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; 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; } // end if l3: if ( 2 == s[ top ].ret ) { top--; goto l2; }else if ( 3 == s[ top ].ret ) { goto l3; } // end nr_hanoi

References Douglas R. Hofstadter, “Gödel, Escher, Bach: an eternal golden braid”, Basic Books, 1999, ISBN 0465026567 Ackermann function at NIST: http://xlinux.nist.gov/dads/HTML/ackermann.html Herbert G Mayer: “Advanced C Programming on the IBM PC”, 1989, Windcrest, ISBN 0-8306-9163-4 Non-recursive solution to Towers of Hanoi: http://portal.acm.org/citation.cfm?id=948602 Herbert G Mayer, Don Perkins, SIGLAN Notices, 1984, non-recursive Towers of Hanoi Solution: http://dl.acm.org/citation.cfm?id=948573