A function is recursive if the body of that function calls itself, either directly or indirectly.
Recursive functions often operate on increasingly smaller instances of a problem.
2 + 0 + 2 + 1 = 5
Fun fact: The sum of the digits in a multiple of 9 is also divisible by 9.
9 * 82 = 738
7 + 3 + 8 = 18
The sum of the digits of 6 is simply 6.
Generally: the sum of any one-digit non-negative number is that number.
The sum of the digits of 2021 is:
Generally: the sum of a number is the sum of the first digits (number // 10
),
plus the last digit (number % 10
).
def sum_digits(n):
"""Return the sum of the digits of positive integer n.
>>> sum_digits(6)
6
>>> sum_digits(2021)
5
"""
if n < 10:
return n
else:
all_but_last = n // 10
last = n % 10
return sum_digits(all_but_last) + last
def sum_digits(n):
if n < 10: # BASE CASE
return n
else: # RECURSIVE CASE
all_but_last = n // 10
last = n % 10
return sum_digits(all_but_last) + last
The factorial of a number is defined as:
$$\begin{equation*} n! = \begin{cases} 1 & \text{if } n = 0 \\ n \cdot (n-1)! & \text{otherwise} \\ \end{cases} \end{equation*}$$
def fact(n):
"""
>>> fact(0)
1
>>> fact(4)
24
"""
if n == 0:
return 1
else:
return n * fact(n-1)
def fact(n):
if n == 0:
return 1
else:
return n * fact(n-1)
fact(3)
def fact(n):
if n == 0:
return 1
else:
return n * fact(n-1)
fact(3)
fact
is called
multiple times
n
evaluates to depends upon
the current environment
fact
solves a simpler
problem than the last: smaller n
fact | → func fact[parent=Global] |
n | 3 | |
Return value | 6 |
n | 2 | |
Return value | 2 |
n | 1 | |
Return value | 1 |
n | 0 | |
Return value | 1 |
If a million dominoes are equally spaced out and we tip the first one, will they all fall?
def fact(n):
"""Returns the factorial of N."""
if n == 0:
return 1
else:
return n * fact(n-1)
Is fact
implemented correctly?
fact
as a functional abstraction!
fact(n-1)
is correct (← the leap!)
fact(n)
is correct
Imagine we're trying to compute 5!
🤔 We ask ourselves, "If I somehow knew how to compute 4!, could I compute 5!?"
💡 Yep, 5! = 5 * 4!
🧝🏽♀️ The fact()
function promises, "hey friend, tell you what, while you're working
hard on 5!, I'll compute 4! for you, and you can finish it off!"
Credit: FuschiaKnight, r/compsci
Used to verify that a credit card numbers is valid.
Original | 1 | 3 | 8 | 7 | 4 | 3 | |
---|---|---|---|---|---|---|---|
Processed | 2 | 3 | 1+6=7 | 7 | 8 | 3 | = 30 |
The Luhn sum of a valid credit card number is a multiple of 10
Let's start with...
def sum_digits(n):
if n < 10:
return n
else:
last = n % 10
all_but_last = n // 10
return last + sum_digits(all_but_last)
def luhn_sum(n):
"""Returns the Luhn sum for the positive number N.
>>> luhn_sum(2)
2
>>> luhn_sum(32)
8
>>> luhn_sum(5105105105105100)
20
"""
def luhn_sum(n):
if n < 10:
return n
else:
last = n % 10
all_but_last = n // 10
return last + luhn_sum_double(all_but_last)
def luhn_sum_double(n):
last = n % 10
all_but_last = n // 10
luhn_digit = sum_digits(last * 2)
if n < 10:
return luhn_digit
else:
return luhn_digit + luhn_sum(all_but_last)
Using recursion: | Using iteration: | |
---|---|---|
|
| |
Math: | $$\small\begin{equation*} n! = \begin{cases} 1 & \text{if } n = 0 \\ n \cdot (n-1)! & \text{otherwise} \\ \end{cases} \end{equation*}$$ | $$n! = \prod_{k = 1}^{n} k$$ |
Names: | fact , n
| fact , n , total , k
|
Can be tricky: Iteration is a special case of recursion.
Figure out what state must be maintained by the iterative function.
def sum_digits(n):
if n < 10:
return n
else:
all_but_last = n // 10
last = n % 10
return sum_digits(all_but_last) + last
def sum_digits(n):
digit_sum = 0
while n >= 10:
last = n % 10
n = n // 10
digit_sum += last
return digit_sum
More formulaic: Iteration is a special case of recursion.
The state of an iteration can be passed as arguments.
def sum_digits(n):
digit_sum = 0
while n >= 10:
last = n % 10
n = n // 10
digit_sum += last
return digit_sum
def sum_digits(n, digit_sum):
if n == 0:
return digit_sum
else:
last = n % 10
all_but_last = n // 10
return sum_digits(all_but_last, digit_sum + last)