+ All Categories
Home > Documents > CS 2130 Lecture 27 Functional Optimizations. Just the factorial... (define fact (lambda (n) (if (= 0...

CS 2130 Lecture 27 Functional Optimizations. Just the factorial... (define fact (lambda (n) (if (= 0...

Date post: 04-Jan-2016
Category:
Upload: audra-barker
View: 213 times
Download: 0 times
Share this document with a friend
32
CS 2130 Lecture 27 Functional Optimizations
Transcript

CS 2130

Lecture 27

Functional Optimizations

Just the factorial...

(define fact

(lambda (n)

(if (= 0 n)

1

(* n (fact (- n 1)))

)

)

)

(define fact (lambda...))

(lambda (n) (if...)

Scheme also allows...

(define (fact n)

(if (= n 0)

1

(* n (fact (- n 1)))

)

)

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

Tail recursion is logically equivalent to a loop!

Just put a goto in place of the recursive call!!!

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;

}

Surely, you're kidding?

Tail recursion is just looping?

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

Questions?

Can you write strlen?

int strlen(char *s)

{

int count = 0;

while(*s != '\0')

{

count++;

s++;

}

return count;

}

Can you write strlen?

int strlen(char *s)

{

int c;

for(c = 0; *s != '\0'; c++, s++);

return c;

}

Can you write it in 1 line?

One liners

int strlen(char *s)

{

return sprintf(s, "%s", s);

}

One liners

int strlen(char *s)

{

return strchr(s, '\0') - s;

}

One liners

int strlen(char *s)

{

return (*s == '\0') ? 0 : 1 + strlen(s+1);

}

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);

}

Questions?


Recommended