g++ -O3 foo.cpp
. -O2
represents that the compiler should optimize the code with optimization-level 3.Examples: Is this tail recursive?
def mystery(n): if (n < 10): return n else: a = n/10 b = n %10 return mystery(a + b)Answer: yes
What about:
def fact(n): if n <= 1: return 1 else: return n * fact(n - 1)Answer: no
Can we rewrite factorial so that it becomes tail-recursive? Tail-recursive factorial:
def factorial_helper(n, accum): if n <= 1: return accum else: return factorial(n - 1, accum * n) def factorial(n): return factorial_helper(n, 1)Tail recursive solutions often end up passing partial computations as parameters that would otherwise be computed after the recursive call.
Compare with non-recursive factorial (sometimes looking at the non-recursive version of a function can help you find the tail recursive solution):
def factorial(n): accum = 1 for i in range(n+1): accum = accum * i return accumThe tail-recursive version often looks like a non-recursive version with a variable or a parameter keeping track of the partial computations. The difference is: the loop is replaced by recursive call.
Another tail-recursion example: fib(n)
def fib_helper(n, i, fib_i, fib_prev): if i == n: return fib_i else: return fib_helper(n, i + 1, fib_i + fib_prev, fib_i) def fib(n): return fib_helper(n, 1, 1, 0)This implementation is similar to the following non-recursive implementation:
def fib(n): i = 1 fib_i = 1 fib_prev = 0 while (i != n): new_i = i + 1 new_fib_i = fib_i + fib_prev new_fib_prev = fib_i fib_i = new_fib_i fib_prev = new_fib_prev i = new_i return fib_i }
Another tail-recursive implementation of fib(n)
with fewer arguments to helper function:
def fib_helper(n, fib_n, fib_prev): if n == 1: return fib_n else: return fib_helper(n - 1, fib_n + fib_prev, fib_n) def fib(n): return fib_helper(n, 1, 0)This implementation is similar to the following non-recursive implementation:
def fib(n): fib_i = 1 fib_prev = 0 while n != 1: new_n = n - 1 new_fib_i = fib_i + fib_prev new_fib_prev = fib_i fib_i = new_fib_i fib_prev = new_fib_prev n = new_n return fib_i
Notice the similarity of tail-recursive implementation to the non-recursive implementation (that uses loops). In general, any loop can be converted to a tail-recursive implementation. In fact, some programming languages do not support loops and only support recursion --- typically programmers write tail-recursive implementations of their programs in such languages.