Take the number 2784. In your head, break it into place values:
2784 = 2000 + 700 + 80 + 4
= 2*1000 + 7*100 + 8*10 + 4*1
Python has two operators that are perfect for taking numbers apart like this:
% — the modulo operator, gives the remainder of a division// — integer division, gives the result of a division with the remainder thrown awayBefore coding, answer these questions:
2784 % 10 to be?2784 // 10 to be?% or // — do you expect gives you the last digit of a number? Which gives you the number with the last digit chopped off?50, for 7, and for 100? Reason about it before running anything.Write a function last_digit(n) that returns the last digit of a non-negative integer n.
Example:
last_digit(2784) # Output: 4
last_digit(7) # Output: 7
last_digit(100) # Output: 0
last_digit(0) # Output: 0
Write a function remove_last_digit(n) that returns n with its last digit chopped off.
Example:
remove_last_digit(2784) # Output: 278
remove_last_digit(7) # Output: 0
remove_last_digit(100) # Output: 10
Think about it: what should remove_last_digit(0) return? Decide before you run it, then check.
Here's a sanity check: for any n, you should be able to rebuild it from remove_last_digit(n) and last_digit(n).
Tasks:
n = 2784, compute remove_last_digit(n) * 10 + last_digit(n) by hand (using the values from Exercises 1.2 and 1.3). Does it equal n?check_roundtrip(n) that returns True if remove_last_digit(n) * 10 + last_digit(n) == n, False otherwise.0 and a single-digit number.When you deposit or borrow money, it grows over time due to interest. The formula for Simple Interest is:
Interest = (Principal * Rate * Time) / 100
where:
Principal — the amount deposited or borrowedRate — the interest rate per year, as a percentageTime — the number of yearsBefore coding, answer these questions:
1000 at a rate of 5% for 2 years, what's the interest, by hand?Time = 0? Does that match your intuition about lending money for zero years?Write a function calculate_interest(principal, rate, time) that returns the simple interest using the formula above.
Example:
calculate_interest(1000, 5, 2) # Output: 100.0
calculate_interest(1500, 4.3, 3) # Output: 193.5
calculate_interest(500, 10, 0) # Output: 0.0
Tasks:
principal = 1000 and rate = 5. Compute the interest for time = 1, 2, 3, ..., 10. What pattern do you notice in how the interest grows as time increases by 1 each time?principal = 1000 and time = 1. Compute the interest for rate = 1, 2, ..., 10. Is the pattern the same kind of growth as in #1?y = m*x + c you may already know).For a right triangle with legs base and height, the Pythagorean theorem says:
hypotenuse**2 = base**2 + height**2
Before coding: work out by hand — if base = 3 and height = 4, what is the hypotenuse?
Write calculate_hypotenuse(base, height) that returns the hypotenuse using the formula above. You can use ** 0.5 or math.sqrt to take the square root.
Example:
calculate_hypotenuse(3, 4) # Output: 5.0
calculate_hypotenuse(5, 12) # Output: 13.0
calculate_hypotenuse(0, 0) # Output: 0.0
A point on a flat plane is given by an (x, y) pair. The distance between two points (x1, y1) and (x2, y2) is exactly the hypotenuse of the right triangle formed by their horizontal and vertical separations.
Before coding:
(0, 0) and (3, 4), what are the lengths of the horizontal leg (base) and vertical leg (height) of the right triangle between them?find_distance_2d(x1, y1, x2, y2).Your derivation:
Write find_distance_2d(x1, y1, x2, y2) that returns the distance between the two points. You can use math.sqrt.
Example:
find_distance_2d(0, 0, 3, 4) # Output: 5.0
find_distance_2d(1, 2, 4, 6) # Output: 5.0
A point in 3D space has three coordinates: (x, y, z).
Before coding: extend your 2D distance formula to three dimensions. What term do you need to add, and why?
Your derivation:
calculate_distance_3d(x1, y1, z1, x2, y2, z2) = ...
Write calculate_distance_3d(x1, y1, z1, x2, y2, z2) that returns the distance between the two 3D points.
Example:
calculate_distance_3d(0, 0, 0, 1, 1, 1) # Output: 1.7320508075688772
calculate_distance_3d(2, 3, 5, 2, 3, 5) # Output: 0.0
calculate_distance_3d(1, 2, 3, 4, 6, 9) # Output: 7.810249675906654
Imagine a taxi that can only drive along a grid of streets — no diagonal shortcuts. The distance it travels between two points is called the Manhattan distance.
Before coding:
(2, 3) to (5, 1), how far would the taxi have to drive if it can only move horizontally and vertically (never diagonally)?manhattan_distance(x1, y1, x2, y2) = ?. (Python's absolute value function is abs(...).)Your derivation:
manhattan_distance(x1, y1, x2, y2) = ...
Example:
manhattan_distance(2, 3, 5, 1) # Output: 5
manhattan_distance(0, 0, 0, 0) # Output: 0
manhattan_distance(-1, -1, 1, 1) # Output: 4
Tasks:
(0, 0) and (3, 4), compute both find_distance_2d and manhattan_distance. Which is bigger?A delivery drone flies in a straight line from point A to point B, but a delivery truck must follow streets laid out in a grid. Which distance formula should you use to estimate each vehicle's travel distance?
A. Euclidean for both
B. Manhattan for both
C. Euclidean for the drone, Manhattan for the truck
D. Manhattan for the drone, Euclidean for the truck
A straight line in 2D can be written as:
y = m * x + c
m — the slope (steepness)c — the intercept (where the line crosses the y-axis)Before coding: if m = 2, c = 3, x = 4, what is y, by hand?
Write predict(m, c, x) that returns y = m * x + c.
Example:
predict(2, 3, 4) # Output: 11
predict(-1, 5, 2) # Output: 3
Use the plotting helper below to see your line. It calls your own predict function under the hood.
Don't worry about understanding the plotting code — we will study it later in class. For now, just run it and use it.
Try plotting a couple of lines:
plot_line(2, 3)
plot_line(-1, 5)
So far you've gone from (m, c, x) to y. Now go the other direction: given two points that lie on a line, figure out the line's m and c.
Before coding:
y changes per one-unit change in x. If you know two points (x1, y1) and (x2, y2) on the line, write a formula for m in terms of these four numbers.m, how can you find c using just one of the two points and the line equation y = m*x + c? (Hint: rearrange the equation to solve for c.)(1, 2) and (3, 6), what are m and c?Your derivation:
Write fit(x1, y1, x2, y2) that returns a tuple (m, c) — the slope and intercept of the line through the two points.
Example:
fit(1, 2, 3, 6) # Output: (2.0, 0.0)
fit(0, 5, 2, 9) # Output: (2.0, 5.0)
Think about it: what happens if
x1 == x2? The line would be vertical, andmwould be undefined (division by zero). You don't need to fix this — just notice it, and let your function do whatever Python naturally does in that case.
Tasks:
fit to recover (m, c) from the points (1, 2) and (3, 6).predict with that (m, c) to compute y at x = 1 and x = 3. Do you get back 2 and 6?x = 5. According to your fitted line, what should y be?plot_line(m, c, extra_points=[(1, 2), (3, 6)]) to check visually.The derivative of a function at a point tells you how fast the function's output is changing there — its instantaneous slope.
You don't need calculus rules to approximate this. Recall Exercise 4.4: the slope between two points is (y2 - y1) / (x2 - x1).
Idea: pick two points on the function's curve that are very close together, and compute the slope between them.
Before coding:
f(x) = x * x, compute f(3) and f(3.0001) by hand.(3, f(3)) and (3.0001, f(3.0001)) as two points on a line, and use the slope formula from Exercise 4.4 to compute the slope between them. This is your approximate derivative of f at x=3.x**2 is 2*x. At x=3 that's 6. How close is your approximation?Your derivation:
Formalize what you just did. This is called the forward difference method:
$$f'(x) \approx \frac{f(x + h) - f(x)}{h}$$
where h is a small number.
Write a function approx_derivative(func, x, h) that:
func of one argument,x,h,func at x.Example:
def square(x):
return x * x
approx_derivative(square, 3, 0.0001) # Output: approx 6
Tasks:
approx_derivative on cube(x) = x*x*x at x=2. The true derivative of x**3 is 3*x**2 — at x=2 that's 12. How close are you?math.sin at x=0. The true derivative of sin(x) at 0 is cos(0) = 1.h gets smaller — try h = 0.1, 0.01, 0.0001, 0.0000001? What about when h gets too small (like 1e-15)? Can you explain what you observe?A function's derivative at a point is the slope of the tangent line — the line that just barely touches the curve there.
Recall from Part 4: a line is y = m*x + c. If you know the slope m (your derivative) and one point on the line, (x0, func(x0)), you can find c using the exact same idea as in Exercise 4.4.
Tasks:
tangent_line_intercept(func, x0, h) that:
approx_derivative(func, x0, h),c such that the tangent line passes through (x0, func(x0)).square at x0 = 3.Use the plotting helper below to see the function and its tangent line together. Pass in the slope and intercept you just computed.
Try it:
x0 = 3
h = 0.0001
m = approx_derivative(square, x0, h)
c = tangent_line_intercept(square, x0, h)
plot_function_with_tangent(square, x0, m, c, x_range=(-1, 6))
You computed approx_derivative(f, 3) and got a value of -2. What does this tell you about the function f at x = 3?
A. f(3) = -2
B. The function is decreasing at x = 3 and its tangent line slopes downward
C. The function reaches its minimum at x = 3
D. The function crosses zero somewhere near x = 3
If you've made it here, you've built a small toolkit of expressions and functions from scratch. These challenges are open-ended — push further if you're curious.
Using last_digit and remove_last_digit from Part 1 (plus a loop), write all_digits(n) that returns a list of n's digits, in order.
all_digits(2784) # Output: [2, 7, 8, 4]
find_distance_2d and calculate_distance_3d look almost identical except for how many coordinates they take. Generalize: write distance_nd(point1, point2) where point1 and point2 are lists of any length (same length as each other), and return the Euclidean distance between them.
distance_nd([0, 0], [3, 4]) # Output: 5.0
distance_nd([0, 0, 0], [1, 1, 1]) # Output: 1.7320508075688772
distance_nd([1, 2, 3, 4], [4, 6, 8, 4]) # 4D!
The forward difference method looks ahead of x only. The central difference method looks on both sides:
$$f'(x) \approx \frac{f(x + h) - f(x - h)}{2h}$$
Write central_derivative(func, x, h) and compare its accuracy against approx_derivative for cube at x=2 (true answer: 12), using the same values of h you tried in Exercise 5.3. Which method gets closer, faster, as h shrinks?
The second derivative tells you how the slope itself is changing. You already have a function that computes a derivative — what happens if you feed approx_derivative a function that is itself a derivative?
Write second_derivative(func, x, h) that approximates $f''(x)$ by applying approx_derivative twice. Test it on cube(x) = x**3, whose second derivative is 6*x — at x=2 that's 12.
You've been writing the same loop again and again: go over a list, do something to each element, collect the results. Capture the pattern once and for all.
Write mymapper(func, lst) that returns a new list containing func(x) for each x in lst. Notice what you're doing: passing a function as an argument, just like you did with approx_derivative.
The other loop you keep writing: combine all the elements into one value (a sum, a product, a maximum...).
Write myreducer(func, lst) where func takes two arguments. Start with the first element, then repeatedly combine the running result with the next element: myreducer(add, [1, 2, 3, 4]) computes add(add(add(1, 2), 3), 4).
If a function can take a function as input, can it also return one as output?
Write create_power_function(p) that returns a new function: the returned function takes x and computes x ** p. So create_power_function(2) builds a squaring function and create_power_function(3) builds a cubing function — one factory, infinitely many functions.
(The returned function "remembers" p even after the factory has finished running — this is called a closure.)
Take a moment to answer these questions in your own words.
% and //? When would you reach for each one?calculate_interest) save you work compared to retyping the formula every time?predict and fit? Which one goes from parameters to data, and which one goes from data to parameters?approx_derivative actually compute? Why doesn't making h as tiny as possible always give a better answer?You've just built a small mathematical toolkit — digit manipulation, formulas as functions, multi-argument functions, line equations, and numerical derivatives. The next chapter, gradient descent, picks up exactly two of these ideas — the line equation y = mx + c and the numerical derivative — and turns them into an algorithm that searches for the best m and c on its own, instead of you computing them by hand from two points.
Source on GitHub · Back to all chapters
© 2026 CloudxLab. All rights reserved.