15. Pushing toward calculus

[status: somewhat written but incomplete]

15.1. Motivation and plan

When I was in school calculus is where math became a pure and never-ending thrill.

Knowing calculus will get us on a path toward science the way it is really done: scientific laws describe how biological or chemical or physical systems change in time and position, and calculus is the mathematics of those changes.

So introducing calculus opens up a fantastic world to us, but how do we teach it to middle and high school kids who have not yet learned the prerequisites?

Our advantage over a pure math class is that we can write programs to illustrate calculus topics. We might not yet know trigonometric and logarithmic identities, but we can write programs to convince ourselves of the properties we have not yet proven. The same goes for limits. This means that we can jump ahead for a while, knowing that in our pure math classes we will eventually prove all the material that we now understand intuitively.

15.2. Prerequisites

  • The 10 hour programming workshop.

  • The mini-courses on elementary and intermediate plotting in Section 2 and Section 3

  • The “tour of functions” mini-course in Section 4.

15.3. Limits, the infinitely big, and the infinitesimally small

Let us plot a function: \(f(x) = 1/x\):

gnuplot> set grid
gnuplot> plot 1/x

We see that it spikes both down and up when x is close to zero, and that it gets closer and closer to zero as x gets very big in the positive direction, and also when x gets very big in the negative direction.

This brings up some questions:

  1. Does \(f(x)\) ever actually reach zero when x gets big?

  2. What is \(f(0)\)? We cannot divide by zero, so the answer cannot be \(f(0) = 1/0\).

There is no clear answer to these questions, but as we begin to grope for answers we might want to say something like:

  1. \(f(x)\) will reach zero when x is infinity, or minus infinity. In formulae: \(f(\infty) = 1/\infty = 0\) and \(f(-\infty) = 1/(-\infty) = 0\).

  2. \(f(0)\) is infinite. So: \(f(0) = 1/0 = \infty\).

But there are several problems with writing down these expressions.

First of all infinity is not an actual number, so we do not have a proper arithmetic for it. We have to define what all of that means.

Then there is the obvious worry that from the plot it looks like \(f(0) = \infty\) (when you look from the right) and \(f(0) = -\infty\) (when you look from the left). This is not OK becuase a function can only have one value at a given point.

The way mathematicians tackle this is with the idea of a limit. Let us start by using this kind of terminology for our \(1/x\) example. For the case of x getting big:

“The limit of \(1/x\) as x goes to infinity is zero.” (And “The limit of \(1/x\) as x goes to minus infinity is zero.”)

And the way we define that is (taking some liberty):

“You can make \(1/x\) arbitrarily close to zero by making \(x\) big enough.”

A more formal way we can say it is:

“For any number (no matter how small) \(\epsilon\), I can find a value \(x_0\) such that, for all \(x > x_0\), \(f(x) < \epsilon\).”

So that allows us to talk about the behavior of \(1/x\) as x gets really big (or really big in the negative direction): we do not say that \(1/\infty = 0\), but rather we say that the limit of \(1/x\) is 0 as \(x\) gets really big. The math notation for this is:

\[\lim_{x\to\infty} \frac{1}{x} = 0\]

although one can also say:

\[\frac{1}{x} \to 0 \; {\rm as } \; x \to \infty\]

And how do mathematicians deal with \(f(0)\)? That’s the one where we have different behavior to the left and to the right of \(x = 0\).

For this mathematicians define a one-sided limit. The way we can talk about \(1/x\) around 0 is:

“The limit of \(1/x\) as x goes to 0 from above is infinity.”

\[\lim_{x\to 0^+} \frac{1}{x} = \infty\]

and

“The limit of \(1/x\) as x goes to 0 from below is minus infinity.”

\[\lim_{x\to 0^-} \frac{1}{x} = -\infty\]

Note

Limits also apply to ordinary functions at ordinary points, not just to unusual situations. For example, \(\lim_{x\to 3} x^2\) is simply \(3^2 = 9\).

15.4. Continuous functions

15.5. Convergence and divergence

We saw that \(f(x) = 1/x\) approaches zero as x goes to infinity. We say that \(f(x)\) converges to zero as x goes to infinity.

We saw that \(f(x) = 1/x\) goes wild at zero. We say that \(f(x)\) diverges as x goes to zero.

Another example clarifies what mathematicians mean by divergence. Take this limit:

\[\lim_{x\to\infty} \sin(x)\]

The \(\sin(x)\) function will bounce around forever, bounded between -1 and +1 forever - it will never settle close to a single value. We say that this function diverges, even though it’s not blowing up to infinity or minus infinity: the fact that it does not converge to a single value means that the limit diverges.

15.6. Weird mixes

Our examples of \(1/0\) and \(1/\infty\) are straightforward, but what if you have a more complex limit, like:

\[\lim_{x\to 0} \sin(1/x)\]

Let us plot this one, and then zoom in to see if it converges:

gnuplot> set samples 1000
gnuplot> plot sin(1/x)
gnuplot> plot [-3:3] sin(1/x)
gnuplot> plot [-1:1] sin(1/x)
gnuplot> plot [-0.5:0.5] sin(1/x)
gnuplot> plot [-0.1:0.1] sin(1/x)
gnuplot> plot [-0.05:0.05] sin(1/x)
gnuplot> plot [-0.01:0.01] sin(1/x)
gnuplot> plot [-0.005:0.005] sin(1/x)
gnuplot> plot [-0.001:0.001] sin(1/x)

We see that there is no convergence, and in fact as you get closer to zero the function looks like it’s less likely to converge on a single value.

Now let us look at:

\[\lim_{x\to 0} x\sin(1/x)\]

and let us plot this slighty different function in the same way:

gnuplot> set samples 1000
gnuplot> plot x*sin(1/x)
gnuplot> plot [-3:3] x*sin(1/x)
gnuplot> plot [-1:1] x*sin(1/x)
gnuplot> plot [-0.5:0.5] *sin(1/x)
gnuplot> plot [-0.1:0.1] x*sin(1/x)
gnuplot> plot [-0.05:0.05] x*sin(1/x)
gnuplot> plot [-0.01:0.01] x*sin(1/x)
gnuplot> plot [-0.005:0.005] x*sin(1/x)
gnuplot> plot [-0.001:0.001] x*sin(1/x)

Or let us automate that:

reset
set samples 5000
set yrange [-1:1]

do for [ii=1:100:1] {
    max = 100.0/(ii*ii)
    print(max)
    plot [-max:max] x*sin(1/x)
    pause 0.03
}

This zooming in shows us that the function \(f(x) = x \sin(1/x)\) does not diverge at \(x = 0\), even though it has that \(1/x\) bit inside. Although we cannot take \(f(0)\), we do have a limit that converges:

\[\lim_{x\to 0}x \sin(1/x) = 0\]

15.7. Limits of some functions

Listing 15.7.1 explore-limit.py – exploring the limiting behavior of some functions.
#! /usr/bin/env python3

def f(x):
    # return 1/x
    return 1/x**2
    # return exp(-x)
    # return exp(-x**2)

epsilon_str = input('give a very small number: ')
epsilon = float(epsilon_str)

x = 1
while f(x) >= epsilon:
    x += 1

print('with the value of x = %g we got f(x) < %g' % (x, epsilon))

15.8. The limit of a series

A summation is the addition of a sequence of numbers. We use the cool gree capital sigma letter \(\Sigma\) as a notation for this. For example, if we want to write Gauss’s formula for the sum of the first 100 numbers:

\[\sum_{k=1}^{100} k = (100 * 101) / 2 = 5050\]

More generally:

\[\sum_{k=1}^{n} k = \frac{n (n+1)}{2}\]

Or the sum of the first 50 values of the harmonic series \(1/k\):

\[\sum_{k=1}^{50} \frac{1}{k}\]

Or the sum of the first \(n\) values of \(1/k^2\):

\[\sum_{k=1}^{n} \frac{1}{k^2}\]

We read this as “The sum of one over k squared with k going from one to n …”

Sometimes we have something called an infinite series, or just series. This is a sum where you keep adding up the elements forever. An example is:

\[\sum_{k=1}^{\infty} \frac{1}{k^2}\]

which looks like the previous example of a finite sum, but where we sum forever.

One question you might ask is “wait, if you add infinitely many things, won’t that diverge?” My first answer is to say that I’m delighted at how you used the word “diverge” so comfortably. The answer to the question is that we are summing an infinite number of terms, but as we add more terms and k gets bigger, \(1/k^2\) gets infinitesimally small! That means that it’s possible that the sum will converge.

Let us write a simple program which tests this:

Listing 15.8.1 explore-series.py - explore whether the infinite sums of \(1/k\) and \(1/k^2\) diverge or converge.
#! /usr/bin/env python3

## compare the infinite sums of 1/k and 1/k^2

N = 500
sum_1_over_k = 0
sum_1_over_k_sq = 0

for k in range(1, N+1):
    sum_1_over_k += 1.0/k
    sum_1_over_k_sq += 1.0/(k*k)
    print(k, '    ', sum_1_over_k, '    ', sum_1_over_k_sq)
../_images/explore-series.svg

Figure 15.8.1 The sum of the sums of \(1/k\) and \(1/k^2\). We see that the sum of \(1/k\) gets smaller but eventually does surpass any point you might pick, while the sum of \(1/k^2\) never grows past \(\frac{\pi^2}{6}\).

A cute fact to note is that:

\[\sum_{k=1}^{\infty} \frac{1}{k^2} = \frac{\pi^2}{6}\]

so you should take a moment to take the result of the third column in the output of explore-series.py, multiply by 6, take the square root, and see if you get \(\pi\).

We have seen two examples of infinite series, one of which converges and the other does not. Note that mathematicians have dozens of interesting ways of proving rigorously that the harmonic series diverges. A proof dating from the middle ages is shown in the Wikipedia article on the harmonic series

15.9. The most important application: derivatives

The most important use we have for limits is to formulate differential and integral calculus.

Differential calculus is the study of the rate of change of functions, while integral calculus is the study of the areas defined by the curves of functions.

We will discuss integrals in Section 16, while we will talk briefly about derivatives here. [FIXME: eventually derivatives might also have their own chapter.]

There are many introductions to calculus, including some written as free documentation, so here I will simply show a couple of figures from the Wikipedia article on derivatives so that an instructor can make reference to those pictures and explain it on a blackboard or whiteboard.

In Figure 15.9.1 we see that a reasonably smooth curve has a tangent line at each point, and the slope of that tangent line (which we know from analytical geometry) is what we call the slope of the curve.

../_images/Tangent-calculus.svg

Figure 15.9.1 The derivative is slope of the the line tangent to the curve at the given point.

But how do we find the slope of this tangent line? In Figure 15.9.2 we see how we might do this:

../_images/Secant-calculus.svg

Figure 15.9.2 To find the tangent line we start with an intersecting (or secant) line that goes through the point \(x\) and a point a tiny bit ahead \(x + h\), where \(h\) is small.

If we take the points \((x, f(x)), (x+h, f(x+h))\) we have a line segment and we can calculate its slope with the usual \(\Delta y/\Delta x\):

\[{\rm derivative\; of\; f\; at\; x} = \frac{f(x+h) - f(x)}{(x + h) - x} = \frac{f(x+h) - f(x)}{h}\]

We use the notation

\[\frac{d f(x)}{dx}\]

for the slope (derivative) of a function f at point x.

The place where limits come in is that if we make h really small then this intersecting line will become the tangent line, and its slope will be the derivative at that point.

Note

The notation \(\frac{df(x)}{dx}\) is called the “Leibniz notation”. Other common ways of writing the derivative are the “Lagrange notation:” \(f'(x)\), and Newton’s “dot” notation which is usually used when we have functions of time:

\[\dot x = \frac{dx}{dt}\]

15.10. Visualizing derivatives with an animation

Drawing the pictures for the derivative on the board might help some, but an animation really drives home the idea of the derivative as a limit.

The program in Listing 15.10.1 shows an animation of the types of plots from a secant line to tangent line. See Figure 15.9.2 and Figure 15.9.1.

Listing 15.10.1 derivative-animation.py - look at the limit as h approaches zero: the secant line becomes a tangent line at the given point.
#! /usr/bin/env python3

import math
import matplotlib.pyplot as plt
import matplotlib
import numpy as np

draw_scale = 4.0

def main():
    # the limits and the function that we plot
    a = -1.3
    b = 3.2
    func = curvy_cubic

    # matplotlib graphics setup - boiler-plate stuff
    plt.rcParams.update({'font.size': 10*draw_scale})
    fig = plt.figure(figsize=(6.4*draw_scale, 4.8*draw_scale))

    # first generate the x for the entire domain from a to be
    x = np.arange(a, b, 1.0/1000)
    # pick the point at which we calculate the derivative
    # x0 = a + 2.0*(b-a)/3
    x0 = 1.8

    ## now a loop in which h gets smaller and smaller
    for i in range(2,300):
        # pick a value of h that keeps decreasing toward 0
        h = 2/(i + 1e-2*i*i)
        # calculate the slope of the secant line
        y0 = func(x0)
        y1 = func(x0+h)
        m = (y1 - y0) / h
        # now get the intercept
        b = y0 - m * x0
        print(x0, h, x0+h, y0, m, b)

        # to animate we clear and then redraw everything
        fig.clear()
        # draw the entire curve
        plt.plot(x, func(x), color='g', linewidth=1.0*draw_scale)
        plt.grid(True)
        # draw the two secant points
        plt.plot([x0], [y0], marker='o', markersize=7*draw_scale, color='red')
        plt.plot([x0+h], [y1], marker='o', markersize=5*draw_scale, color='black')
        # draw the line through those two points, using the linear
        # equation y = m*x + b
        line_x_pts = np.arange(x0 - 1.2, x0 + 1.2, 1.0/100)
        line_y_pts = m * line_x_pts + b
        plt.plot(line_x_pts, line_y_pts, color='b', linewidth=1.0*draw_scale)
        # annotate the current value of h and slop
        info_para = """func: %s\nh: %g\nslope: %g""" % (func.__name__, h, m)
        plt.annotate(
            info_para,
            xy=(0, -2), xytext=(0, -2))
        # now annotate where (x0, y0) and (x0+h, y1) are
        plt.annotate('(x0, y0)', xy=(x0, y0), xytext=(x0-1, y0-3),
                     arrowprops=dict(facecolor='black', shrink=0.05))
        plt.annotate('(x0+h, y1)', xy=(x0+h, y1), xytext=(x0+h+1, y1+2),
                     arrowprops=dict(facecolor='black', shrink=0.05))
        # to animate we do the draw_idle() and pause()
        fig.canvas.draw_idle()
        plt.pause(1.45+h)

    plt.waitforbuttonpress()

def curvy_cubic(x):
    """a simple cubic function mixed with a sin - it shows some
    interesting curves"""
    return (x-1)**3 - 3*(x-1) + np.sin(x)

main()