Date post: | 04-Jan-2016 |
Category: |
Documents |
Upload: | audra-barker |
View: | 213 times |
Download: | 0 times |
Just the factorial...
(define fact
(lambda (n)
(if (= 0 n)
1
(* n (fact (- n 1)))
)
)
)
(define fact (lambda...))
(lambda (n) (if...)
So to calculate...
(fact 5)
(* 5 (fact 4))
(* 5 (* 4 (fact 3)))
(* 5 (* 4 (* 3 (fact 2))))
(* 5 (* 4 (* 3 (* 2 (fact 1)))))
(* 5 (* 4 (* 3 (* 2 (* 1 (fact 0))))))
.
.
.
.
120
StackStack
Tim
eT
ime
But we could use tail recursion
(define (tailfact n result)
(if (= n 0)
result
(tailfact (- n 1) (* n result))))
(define (fact n)
(tailfact n 1))
Analysis
• (fact 5)• (tailfact 5 1)• (tailfact 4 5)• (tailfact 3 20)• (tailfact 2 60)• (tailfact 1 120)• (tailfact 0 120)• 120
StackStack
Tim
eT
ime
But how does it work?
• Tail recursion requires two elements– The tail recursive module must terminate
with a recursive call that leaves no work on the stack to finish up. Any storage then must be done in the parameter list as opposed to the stack
– The interpreter or compiler must be designed to recognize tail recursion and handle it appropriately
Return to C
int tailfact(int n, int result)
{
if(n == 0)
{
return result;
}
else
{
return tailfact(n - 1, result * n);
}
Recall that this function Recall that this function will be called like:will be called like:tailfact(5,1)tailfact(5,1)
Put arg calcs into assignments
int tailfact(int n, int result)
{
if(n == 0)
return result;
else
{
result = result * n;
return tailfact(n - 1, result);
}
Put arg calcs into assignments
int tailfact(int n, int result)
{
if(n == 0)
return result;
else
{
result = result * n;
n = n - 1;
return tailfact(n, result);
}
Substitute goto beginningin place of recursive call
int tailfact(int n, int result)
{
beginning:
if(n == 0)
return result;
else
{
result = result * n;
n = n - 1;
goto beginning;
}
If you're a fan of N. Wirth
int tailfact(int n, int result)
{
while(1)
{
if(n == 0)
return result;
result = result * n;
n = n - 1;
}
return ERROR;
}
Let's look at what the compiler actually does
int headfact(int n)
{if(n == 0){
return 1;}else{
return n * headfact(n-1);}
}
Squint!# Head Recursion No Optimization
.file "head.c"
gcc2_compiled.:
.global .umul
.section ".text"
.align 4
.global headfact
.type headfact,#function
.proc 04
headfact:
!#PROLOGUE# 0
save %sp, -112, %sp # Make frame by moving stack pointer
!#PROLOGUE# 1 # (Macro which also adjust %fp)
st %i0, [%fp+68] # Put para passed in reg into n on stk
ld [%fp+68], %o0 # Put n into Reg o0
cmp %o0, 0 # Is it zero?
bne .LL3 # If not branch to calc n*fact(n-1)
nop
mov 1, %i0 # Put 1 into Reg i0 (Return value)
b .LL2 # Jump to return code
nop
b .LL4
nop
.LL3:
ld [%fp+68], %o0 # Put n into Reg o0
add %o0, -1, %o1 # Subtract 1 result into Reg o1
mov %o1, %o0 # Put result back into Reg o0
call headfact, 0 # Call fact(n-1)
nop
mov %o0, %o1 # Waste time?
mov %o1, %o0 # fact of (n-1) is in Reg o0
ld [%fp+68], %o1 # Put n into Reg o1
call .umul, 0 # Multiply Regs o0 and o1
nop
mov %o0, %i0 # Put result into return Reg i0
b .LL2 # Jump to return code
nop
.LL4:
.LL2:
ret # Setup for return
restore # Restore stack and
.LLfe1:
.size headfact,.LLfe1-headfact
.ident "GCC: (GNU) 2.95.1 19990816 (release)"
headfact:
save %sp, -112, %sp # Make frame
st %a0, [%sp+68] # Put para passed into n
ld [%sp+68], %o0 # Put n into Reg o0
cmp %o0, 0 # Is it zero?
bne .CALC # If not branch to calc
mov 1, %rr # Put 1 into Reg i0
b .RETURN # Jump to return code
.CALC:
ld [%fp+68], %o0 # Put n into Reg o0
add %o0, -1, %o1 # Put n-1 int Reg o1
mov %o1, %a0 # Put n-1 into arg reg
call headfact # Call fact(n-1)
mov %rr, %o0 # Put return val into reg
ld [%fp+68], %o1 # Put n into Reg o1
call .umul # Multiply Regs o0 and o1
mov %o0, %rr # Put result into return Reg
.RETURN:
restore
retLaundered CodeLaundered Code
Now tail recursion
int tailfact(int n, int result)
{if(n == 0){
return result;}else{
return tailfact(n-1, result*n);}
}
Non-optimized
tailfact:
save %sp, -112, %sp # Make frame
st %a0, [%fp+68] # Put arg0 into n
st %a1, [%fp+72] # Put arg1 into result
ld [%fp+68], %o0 # Put n into reg
cmp %o0, 0 # Is it 0?
bne .CALC # No, go to calc
ld [%fp+72], %rr # Yes, put result into %rr
b .RETURN
Laundered CodeLaundered Code
Non-optimized
.CALC:
ld [%fp+68], %o0 # Put n into reg
add %o0, -1, %a0 # Put n-1 into arg0
ld [%fp+72], %o0 # Put result into reg
ld [%fp+68], %o1 # Put n into reg
call .umul # Multiply (n*result)
mov %o0, %a1
call tailfact # Note return will be in %rr
.RETURN:
restore
ret
Laundered CodeLaundered Code
Optimized
tailfact:
save %sp, -112, %sp # Build frame
mov %a0, %l0 # Put arg0 into Reg for n
mov %a1, %O0 # Put result into reg
.Loop:
cmp %l0, 0 # Does n == 0?
be .RETURN
mov %l0, %o1 # Put n into Reg
call .umul # Mult n * result
add %l0, -1, %l0 # n = n - 1
b .LOOP # A loop!!!
.RETURN:
mov %o0, %rr # Put result into ret reg
restore
ret Laundered CodeLaundered Code
Can you write strlen?
int strlen(char *s)
{
int count = 0;
while(*s != '\0')
{
count++;
s++;
}
return count;
}
One liners with helper?
int strlen(char *s)
{
return strlnt(s, 0);
}
int strlnt(char *s, int count)
{
return (*s == '\0') ? count
: strlnt(s+1,count+1);
}
One liners with macro?
#define strlen(s) strlnt((s), 0)
int strlnt(char *s, int count)
{
return (*s == '\0') ? count
: strlnt(s+1,count+1);
}