1.6. Recursion#

Reference: Chapter 3 of Computational Nuclear Engineering and Radiological Science Using Python, R. McClarren (2018)

1.6.1. Learning Objectives#

After studying this notebook, completing the activities, and asking questions in class, you should be able to:

  • Understand the concept of recursion with functions.

1.6.2. Recursion#

The idea behind recursion is that a function can call itself. That is really it. That capability can allow some neat tricks, but in practice there is often a faster way of doing things than using recursion.

Home Activity

Write pseudcode to calculate the factorial of integer x two ways: i) without recursion and ii) with recursion.

Class Activity

Explain your pseudocode to a partner. One person explains without recursion and the other explains with recurison.

Below are two functions that calculate factorial with and without recurision.

def factorial(n, prev=1):
    if not((n==1) or (n==0)):
        prev = factorial(n-1,prev)*n
    return prev

def factorial_no_recursion(n):
    output = 1;
    #can skip 1 because x*1 = 1
    for i in range(2,n+1):
        output = output*i
    return output
x = int(input("Enter an integer: "))
print(x,"! =",factorial(x))
print(x,"! =",factorial_no_recursion(x))
10 ! = 3628800
10 ! = 3628800

Let’s see which is faster. This will use some ipython magic commands for timing execution. We’ll compute the factorials of 0 through 20, 100,000 times.

%%time
for times in range(10**5):
    for n in range(21):
        factorial(n)
CPU times: total: 10.1 s
Wall time: 10.1 s
%%time
for times in range(10**5):
    for n in range(21):
        factorial_no_recursion(n)
CPU times: total: 3.86 s
Wall time: 3.94 s

Side-tangent: wall versus CPU user versus CPU clock time: https://stackoverflow.com/questions/7335920/what-specifically-are-wall-clock-time-user-cpu-time-and-system-cpu-time-in-uni (Side-tangents will not appear in tests or assignments, but are given to satisfy your curiosity.)

The no recursion version, while not as neat, is nearly 50% faster. It is also possible to have too many levels of recursion.

import sys
sys.setrecursionlimit(1000) # change this to answer the home activity question
x = 1000
#this won't work and prints ~1000 errors
#the errors are not repeated here
print(x,"! =",factorial(x))
---------------------------------------------------------------------------
RecursionError                            Traceback (most recent call last)
Input In [4], in <cell line: 6>()
      3 x = 1000
      4 #this won't work and prints ~1000 errors
      5 #the errors are not repeated here
----> 6 print(x,"! =",factorial(x))

Input In [1], in factorial(n, prev)
      1 def factorial(n, prev=1):
      2     if not((n==1) or (n==0)):
----> 3         prev = factorial(n-1,prev)*n
      4     return prev

Input In [1], in factorial(n, prev)
      1 def factorial(n, prev=1):
      2     if not((n==1) or (n==0)):
----> 3         prev = factorial(n-1,prev)*n
      4     return prev

    [... skipping similar frames: factorial at line 3 (969 times)]

Input In [1], in factorial(n, prev)
      1 def factorial(n, prev=1):
      2     if not((n==1) or (n==0)):
----> 3         prev = factorial(n-1,prev)*n
      4     return prev

Input In [1], in factorial(n, prev)
      1 def factorial(n, prev=1):
----> 2     if not((n==1) or (n==0)):
      3         prev = factorial(n-1,prev)*n
      4     return prev

RecursionError: maximum recursion depth exceeded in comparison

Home Activity

What is the smallest recursion limit for which factorial(1000) works?

x = 1000
#this works
answer = factorial_no_recursion(x)
print(x,"! =",answer)
1000 ! = 402387260077093773543702433923003985719374864210714632543799910429938512398629020592044208486969404800479988610197196058631666872994808558901323829669944590997424504087073759918823627727188732519779505950995276120874975462497043601418278094646496291056393887437886487337119181045825783647849977012476632889835955735432513185323958463075557409114262417474349347553428646576611667797396668820291207379143853719588249808126867838374559731746136085379534524221586593201928090878297308431392844403281231558611036976801357304216168747609675871348312025478589320767169132448426236131412508780208000261683151027341827977704784635868170164365024153691398281264810213092761244896359928705114964975419909342221566832572080821333186116811553615836546984046708975602900950537616475847728421889679646244945160765353408198901385442487984959953319101723355556602139450399736280750137837615307127761926849034352625200015888535147331611702103968175921510907788019393178114194545257223865541461062892187960223838971476088506276862967146674697562911234082439208160153780889893964518263243671616762179168909779911903754031274622289988005195444414282012187361745992642956581746628302955570299024324153181617210465832036786906117260158783520751516284225540265170483304226143974286933061690897968482590125458327168226458066526769958652682272807075781391858178889652208164348344825993266043367660176999612831860788386150279465955131156552036093988180612138558600301435694527224206344631797460594682573103790084024432438465657245014402821885252470935190620929023136493273497565513958720559654228749774011413346962715422845862377387538230483865688976461927383814900140767310446640259899490222221765904339901886018566526485061799702356193897017860040811889729918311021171229845901641921068884387121855646124960798722908519296819372388642614839657382291123125024186649353143970137428531926649875337218940694281434118520158014123344828015051399694290153483077644569099073152433278288269864602789864321139083506217095002597389863554277196742822248757586765752344220207573630569498825087968928162753848863396909959826280956121450994871701244516461260379029309120889086942028510640182154399457156805941872748998094254742173582401063677404595741785160829230135358081840096996372524230560855903700624271243416909004153690105933983835777939410970027753472000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

By the way, I’m surprised it is giving the correct answer.