Using Programming to Teach Mathematics

It is often argued that programmers need a solid mathematical background in order to be competent in their chosen profession.

Discrete mathematics offers a great foundation for programming, don’t get me wrong, but the truth is that most programmers can get away with knowing very little in the way of mathematics.

In fact, if you are afraid to give programming a go because you’re scared or intimidated by the mathematics that it may require, I have both good and bad news for you. The good news is that you don’t need to know a lot of math, so go ahead and grab that, say, Python tutorial. The bad news is that you’re on the wrong website.

Jokes aside, there is a distinction between Computer Science (which is applied mathematics) and many forms of programming in the real world. As someone who loves both of these fields, I actually wish more mathematics were required for typical programming tasks, but that’s really not the case outside of specific areas (e.g., the way Statistics is required for Data Science for example).

Interested in web development? Want to build phone apps? Generally speaking, you’ll be able to get away with high school level mathematics. Often even less.

I would argue, however, in favor of leveraging programming as a tool to gain a greater understanding of mathematics, benefiting in many cases from the insight derived from looking at problems from a different perspective.

Exploring Limits

Take limits for example. The formal (ε, δ)-definition can be quite abstract for some students. However, assuming that they had basic programming under their belt, they could better understand the concept of limits by implementing a basic loop to calculate one numerically or verifying a limit by seeing what happens to delta as we make epsilon smaller.

Or, again, numerically attest that

[tex]\displaystyle \lim_{x \to 0^{+}}\sin{\frac{1}{x}}[/tex]

is undefined because the values of the function keep bouncing up and down as we approach 0.

For example, in Python:

from math import sin

iterations = 25
y = []

for i in range(iterations):
    x = 10**(-i)
    y.append(sin(1/x))

print(y)

This outputs:

[0.8414709848078965, 
-0.5440211108893699, 
-0.5063656411097588, 
...
-0.46453010483537266, 
0.6026736248210984, 
-0.9270631660486504, 
-0.6452512852657808, 
-0.7723695610856443, 
-0.8522008497671888, 
-0.9404597602708659, 
-0.9940190314626683]

In this case, we start with n = 1, then 0.1, then 0.01, and so on at each iteration. Therefore the variable iterations cannot be a large number.

With a large number of iterations we quickly reach values of x so close to zero that Python will consider them to be actually zero and, in turn, raise an error when we try to use them as the denominator.

Yet I’m not happy about how the last values for 25 iterations almost appear to converge to -1. We need to investigate further.

We can note that [tex]1/10^{-i} = 10^{i}[/tex] and rewrite the snippet as follows:

from math import sin

iterations = 300
y = []

for i in range(iterations):
    y.append(sin(10**i))

print(y[-10:])

Which outputs the last 10 values calculated:

[0.989437258784857,
-0.4966901940922658,
-0.9103772753628088,
0.8800821363463286,
-0.6332838747003383, 
0.9715807677312862,
-0.6829752972358332,
0.9845286610301919,
0.9218407151906046, 
0.7491022024187135]

Good. We went as small as [tex]x=10^{-299}[/tex] and we are still oscillating between -1 and 1.

Keep in mind that the iterations variable must be limited in the snippet above as well. On my machine, with Python 3.5, I was limited to a little over 300 iterations before getting an overflow error. (We can avoid such limitations but it’s beyond the scope of this post, as well as language dependent.)

Let me be clear:

There is nothing rigorous about what we are doing here.

We can be fooled by plausible but false examples, run into floating point arithmetic errors if we are not careful (try [tex]0.3-0.2-0.1[/tex] in your favorite programming language), and so on.

The point, however, is to explore mathematical concepts through programming so as to gain more insight and a deeper intuitive understanding of what’s going on, where possible.

Exploring Sums

We can play with sums as well. Take for example the well known converging geometric series:

[tex]\displaystyle \sum_{n=0}^{\infty}{2^{-n}}[/tex]

Students could write a trivial program to verify that the sum converges to 2, and then examine how quickly it does so.

For example, in Python:

sum = 0

for n in range(100):
    sum += 2**(-n)
    print("n: {} -> {}".format(n, sum))

Which prints:

n: 0 -> 1
n: 1 -> 1.5
n: 2 -> 1.75
n: 3 -> 1.875
n: 4 -> 1.9375
n: 5 -> 1.96875
n: 6 -> 1.984375
n: 7 -> 1.9921875
n: 8 -> 1.99609375
n: 9 -> 1.998046875
n: 10 -> 1.9990234375
n: 11 -> 1.99951171875
n: 12 -> 1.999755859375
n: 13 -> 1.9998779296875
n: 14 -> 1.99993896484375
n: 15 -> 1.999969482421875
n: 16 -> 1.9999847412109375
n: 17 -> 1.9999923706054688
n: 18 -> 1.9999961853027344
n: 19 -> 1.9999980926513672
n: 20 -> 1.9999990463256836
n: 21 -> 1.9999995231628418
n: 22 -> 1.999999761581421
n: 23 -> 1.9999998807907104
n: 24 -> 1.9999999403953552
n: 25 -> 1.9999999701976776
n: 26 -> 1.9999999850988388
n: 27 -> 1.9999999925494194
n: 28 -> 1.9999999962747097
n: 29 -> 1.9999999981373549
n: 30 -> 1.9999999990686774
n: 31 -> 1.9999999995343387
n: 32 -> 1.9999999997671694
n: 33 -> 1.9999999998835847
n: 34 -> 1.9999999999417923
n: 35 -> 1.9999999999708962
n: 36 -> 1.999999999985448
n: 37 -> 1.999999999992724
n: 38 -> 1.999999999996362
n: 39 -> 1.999999999998181
n: 40 -> 1.9999999999990905
n: 41 -> 1.9999999999995453
n: 42 -> 1.9999999999997726
n: 43 -> 1.9999999999998863
n: 44 -> 1.9999999999999432
n: 45 -> 1.9999999999999716
n: 46 -> 1.9999999999999858
n: 47 -> 1.999999999999993
n: 48 -> 1.9999999999999964
n: 49 -> 1.9999999999999982
n: 50 -> 1.9999999999999991
n: 51 -> 1.9999999999999996
n: 52 -> 1.9999999999999998
n: 53 -> 2.0
n: 54 -> 2.0
n: 55 -> 2.0
...

We can see that it converges quite fast. By the time n is only 53, the sum is already a number so close to 2 that Python considers it to be 2.

Probability and Montecarlo Simulations

Stepping away from Calculus, programming is also a particularly handy tool for students who are tackling Probability Theory.

For example, the Monty Hall problem even managed to fool some seasoned mathematicians. Running a simple simulation we can quickly see that switching doors is the winning strategy (and that we’ll win roughly 66.66% of the times by doing so).

Simulations and Monte Carlo methods are not just a study aid, in some cases, they’re the only reasonable approach to solving problems.

Experimental mathematics

The same exploratory mindset that’s used to provide more insight to students can be stretched all the way to the field of experimental mathematics (a field that I happen to personally find particularly interesting).

Wikipedia defines experimental mathematics as follows:

Experimental mathematics is an approach to mathematics in which numerical computation is used to investigate mathematical objects and identify properties and patterns. It has been defined as “that branch of mathematics that concerns itself ultimately with the codification and transmission of insights within the mathematical community through the use of experimental (in either the Galilean, Baconian, Aristotelian or Kantian sense) exploration of conjectures and more informal beliefs and a careful analysis of the data acquired in this pursuit.

I suspect that Ramanujan used a similar approach, only without a computer and with an incredible degree of mathematical intuition, to come up with much of his work.

What’s important is that exploratory mindset, today aided by the computer, which can then be met by rigor or formalization once we have an intuitive understanding.

In conclusion, math does indeed serve programmers well, but the reverse is also true. Programming can serve students of mathematics (at all levels) remarkably well.

7 Comments

  1. Thomas July 29, 2016
  2. Peter Uelkes August 16, 2016
  3. Peter Farrell August 21, 2016
  4. IdPnSD September 17, 2016
    • Antonio Cangiano September 17, 2016
  5. Nate Zimmer May 7, 2017

Leave a Reply