CS150 - Fall 2011 - Class 19
exercises
admin
- CS talk, Wednesday at 12:30 in MBH 104
- pizza at 12:20
- extra credit for attending
recursion limit
- python has a default recursion limit set
- if the "stack" gets more entries on it than this limit, you'll get an exception:
>>> factorial(1000)
...
RuntimeError: maximum recursion depth exceeded
- There are situations where the default recursion limit is not sufficient
- the default is 1000
- this is the maximum stack size and other functions may also end up on the stack so you may not actually be able to recurse this many times
- you can increase the limit from the sys module:
import sys
sys.setrecursionlimit(10000)
- now we can call our factorial function with larger numbers:
>>> factorial(1000)
4023872600770937...
the four steps to writing a recursive function:
1. define what the function header is
2. define the recursive case
3. define the base case
4. put it all together
power function
- At the end of class we wrote a recursive function called power that took two parameters, a base and an exponent, and calculated base^exponent
- recursive case: b^e = b * b^e
- base case: e = 0
- look at power function in
recursion.py code
how many times is power called?
- exponent+1 times
- power(base, exponent)
- power(base, exponent-1)
- power(base, exponent-2)
- ...
- power(base, 1)
- power(base, 0)
- can we do any better efficiency-wise (that is, less calls to exponent)?
- observation: what if e is even?
- b^e = b^(e/2) * b^(e/2)
- look at fast_power function in
recursion.py code
- two different recursive cases
- if the exponent is even
- b^e = b^(e/2) * b^(e/2)
- if the exponent is odd
- our normal recursive case
- b^e = b * b^(e-1)
- why is this faster?
- when it's even, instead of just decreasing by 1, we decrease by a half!
look at the spiral function in
turtle_recursion.py code
- for example, what would the picture look like if I called:
>>> spiral(80, 50)
- what does this function do?
- recursive function
- draws a spiral on the screen
- forward 80
- left 30
- spiral( 76, 49 )
- forward 76
- left 30
- spiral(72.2, 48)
- forward 72.2
- left 30
- ...
- when does it stop?
- when levels == 0
- repeat 50 times:
- forward length
- left 30
- reduce length by 5%
- what if we wanted to end up back at the starting point, but we couldn't pick the pen up?
- one way would be to trace our steps backward
- Assume that the recursive call returns back to its starting point. What would we need to do to make sure that our call returned back to the starting point?
- Add the following after the recursive call:
right(30)
backward(length)
- if we run it now, we draw the spiral all the way down, and then we retrace backwards
- why does this work?
- each call to spiral retraces its own part after the recursive call
- the stack keeps track of each of the recursive calls
run broccoli_demo function in
turtle_recursion.py code
1. define what the function header is
- broccoli(x, y, length, angle)
2. define the recursive case
- broccoli is a line with three other broccolis at the end
- one directly straight out
- one 20 degrees to the left
- one 20 degrees to the right
- the three other broccolis should be smaller/shorter than the current
3. define the base case
- eventually the length of the broccoli to be drawn gets too short
- at that point instead of recursing, we draw a yellow dot at the end and stop recursing
4. put it all together
- look at broccoli function in
turtle_recursion.py code
- draw a line in the direction specified
- check the base case
- if the line length is less than 10, just put a yellow dot at the end
- otherwise, it's the recursive case
- draw three smaller broccolis at different angles
- what are new_x and new_y?
- the ending coordinates of the line being drawn
- why do we need to save them?
- after the first recursive call to broccoli the turtle won't be in the same place
- if we turn tracing back on, what will we see, that is, what order will it draw in?
- going to go right (angle -20) over and over again until it gets too short
- it will end the recursion then draw a short center
- this also will be a base case and draw the left
- then it will start to work it's way back up
- eventually, it will make it back up to the top-level and start drawing the center stalk
- after drawing the center stalk, it will draw the left stalk
- how many lines does the program draw?
- a lot! :)
- how could we figure out how many?
- change broccoli so that it returns the number of lines that it draws
- base case:
- the base case only consists of a single line (followed by a dot)
- add "return 1" after drawing the dot
- recursive case:
- consists of 1 line plus all of the lines in the three recursive broccolis
- save the return values from each of the recursive calls
- return the sum of these values plus 1
c1 = broccoli(new_x, new_y, length * 0.75, angle - 20)
c2 = broccoli(new_x, new_y, length * 0.75, angle)
c3 = broccoli(new_x, new_y, length * 0.75, angle + 20)
return c1 + c2 + c3 + 1
- 3280 lines!