Saturday, 5 January 2013


An item in the Sydney Morning Herald's Column 8 mentioned the following interesting mathematical tidbit - 2013 is the start of a uncommon triplet of years which are all the products of three distinct primes - 2013 = 3 x 11 x 61,  2014 = 2 x 19 x 53, and 2015 = 5 x 13 x 31.

When did this last happen? In 1885 (5 x 13 x 29),  1886 (2 x 23 x 41), 1887 (3 x 17 x 37), and before that, only in the years 1309 (7 x 11 x 17), 1310 (2 x 5 x 131), 1311 (3 x 19 x 23). It won't happen again until 2665 (5 x 13 x 41), 2666 (2 x 31 x 43), 2667 (3 x 7 x 127).

After that, the next such triplets are 3729-3731 and 5133-5135, but then it happens 5 times in the 7th millenium (6061-6063, 6213-6215, 6477-6479, 6853-6855 and 6985-6987).

So if you want to stimulate a discussion about factors and/or prime numbers, 2013 is a great year.

Wednesday, 10 October 2012

When True Was True When It Should Have Been False

(or Why The Devil Is In The Details)

Another 'whoops' moment in class today - another little lesson learned by the teacher: always read the documentation carefully.

In this case, my students had been given the problem of how to 'clean up' a list in Python so that it contained only integers or floats – any strings, tuples, booleans, etc. would need to be removed.

A simple enough task - simply loop over the list and check the type of each item. But here's where the documentation (or more precisely, a cursory read of it) lead us astray.

The Python docs say this about the inbuilt type() function:
Return the type of an object. The return value is a type object. The isinstance() built-in function is recommended for testing the type of an object.
So we should use isinstance()? Okay, let's look at that then:
isinstance(object, classinfo)
Return true if the object argument is an instance of the classinfo argument, or of a (direct or indirect) subclass thereof.
So, we can do something like isinstance(i, (int, float)) to check the if the type of i is an integer or float.

And all seemed well right up to the point when this list:
[3, 4.5, "word", True, (3, 5)]
should have been reduced to:
[3, 4.5]
but instead became:
[3, 4.5, True]
Wha...? How did that boolean slip through?

Back to the documentation:
isinstance(object, classinfo)
Return true if the object argument is an instance of the classinfo argument, or of a (direct or indirect) subclass thereof
When we look at the documentation on numeric data types, we find this:
There are four distinct numeric types: plain integers, long integers, floating point numbers, and complex numbers. In addition, Booleans are a subtype of plain integers.
So this:
isinstance(True, int)
returns True rather than False.

I can see some good reasons why booleans have been defined as a subtype of integers (and it's not only Python where this is the case), but it caught us offguard all the same.

So the point of today's lesson - read the documentation carefully, make sure you get your head around the finer details. Not the point I had planned to make, but maybe a better lesson as a result.

Tuesday, 20 March 2012

You learn something new every day

Today I attempted to correct a problem in a FileMaker database - and screwed it up badly. (Thank goodness for back-ups.)

The problem concerned some data that had not transferred properly during a change-over between two systems - some dates in the old system had appeared in the new as plain integers instead of dates.

A quick experiment showed me that the GetAsDate() function in FileMaker Pro would convert the number to the correct date - simple. So I duly went ahead and made the change to the data in-place. I know better than to do this, of course, but I was in a hurry and didn't want to take the time to export out the data, convert it and import it back in. So you can imagine my expression when those numbers turned not into the dates I was expecting, but instead into question marks, Filemaker's way of indicating that the data was now invalid.

Grabbed a back-up and retrieved the numbers, but what went wrong?

Doing what I should have done first time, and examining matters more thoroughly, I discovered something that I would not have expected. My initial experiment involved taking a number from a number field and converting it using GetAsDate(). But in the actual database, I was taking numbers from a date field and trying to convert them using GetAsDate(), and this doesn't work. It seems that retrieving a number (invalid data) from a date field does not return the number, and GetAsDate() consequently fails.

It became more interesting when I tried (on a separate file derived from the back-up) to use GetAsNumber() on those numbers in the date field - they all came back as 0. Okay, that doesn't work.

So, one more try - what does GetAsText() return? Aha! I get the number - as a text string. But now I have my answer - GetAsDate(GetAsNumber(GetAsText(theDate))). Problem solved.

You learn something new every day. And sometimes you get to learn an old lesson all over again.

Tuesday, 21 February 2012

A Pythagorean Curiosity

Today a colleague asked me to construct a nice question around Pythagoras' Theorem.

Toying with various ideas, I came up with the following figure:

Now it's easy enough to replace a, b, d and e with values, scrub c and one of the right angle symbols and then ask the students to show that the triangle must be right angled. But of course I wanted a nice set of integers for this question, so I wrote a little Python program to generate integer solutions to the set of equations:

Here's the first 30 solutions (given in the form {a, b, c, d, e}):

{9,12,15,20,25}, {16,12,20,15,25}, {18,24,30,40,50}, {25,60,65,156,169}, {27,36,45,60,75}, {32,24,40,30,50}, {36,48,60,80,100}, {45,60,75,100,125}, {48,36,60,45,75}, {49,168,175,600,625}, {50,120,130,312,338}, {54,72,90,120,150}, {63,84,105,140,175}, {64,48,80,60,100}, {64,120,136,255,289}, {72,96,120,160,200}, {75,180,195,468,507}, {80,60,100,75,125}, {81,108,135,180,225}, {90,120,150,200,250}, {96,72,120,90,150}, {99,132,165,220,275}, {100,240,260,624,676}, {108,144,180,240,300}, {112,84,140,105,175}, {117,156,195,260,325}, {125,300,325,780,845}, {126,168,210,280,350}, {128,96,160,120,200}, {128,240,272,510,578}

What stood out was that in most of these, e was a multiple of 5. When I isolated the instances where e was not a multiple of 5, I found that either a or b was!

My first version of my Python program only examined values of a and b up to 1000, so of course I ramped it up a little - to values up to 1000000 for both a and b.

And it still appears to be true. In every solution my program has generated, either e is a multiple of 5 or a or b is.

Looker closer at Pythagorean triplets in general, it is known that at least one number in a Pythagorean triplet has to be a multiple of 5. So if a and b are not multiples of 5, c must be. But if c is a multiple of 5, the Pythagorean triplet of {c, d, e} does not require that e also be a multiple of 5, and yet that appears to be the case for the figure at the top if it is to have integer sides where a and b are not multiples of 5.

Now if I could prove that this it always the case!

Update: when I showed this to another colleague, she pointed out the obvious fact that I had overlooked, namely that the two triangles in the diagram are similar.

Now the matter becomes simple.

Suppose that a is a multiple of 5. Given that the triangles are in the ratio a:c and a and c are the corresponding sides of the two triangles, we find that
and for e to be an integer would mean that c2 must be divisible by a and therefore divisible by 5, and therefore c must be. So both a and c will be multiples of 5. Now it's easy to show that if two of the numbers in a Pythagorean triplet are multiples of 5, the third must be a multiple of 5 as well, so we conclude that if a is a multiple of 5, so are b and c.

What if a is not a multiple of 5? As at least one number in a Pythagorean triplet must be a multiple of 5, if a is not, then either b or c is.

If b is the multiple of 5, c will not be. As stated before, the triangles are in the ratio a:c, so we find
and therefore d is also a multiple of 5. As c is not, we conclude that e is also not a multiple of 5.

The third possibility is that c is the multiple of 5. Again, noting that

but this time, where a and b are not divisible by 5, we conclude that e must be a multiple of 5 as well, and thus d must be as well.

So we find that the possibilities are as follows:
  • if a is a multiple of 5, b and c are multiples of 5 as well (and d and e may be as well)
  • if a is not a multiple of 5 but b is, then d is as well but c and e are not
  • if a and b are not multiples of 5, c must be, and d and e will be as well
Now I can sleep!

Wednesday, 24 August 2011

A Little Geogebra

I am getting to really like Geogebra. I've had my Year 8 class working on it to explore the properties of quadrilaterals, and my wunderkind Mitchell is now exploring circle geometry with it.

This week I was introducing Yr 8 to linear functions. The textbook does the usual dull thing of showing a table of values like this:

x 1 2 3 4 5
y 1 3 5 7 9

and asking the students to determine the 'rule' that connects x and y.

But I have a laptop and a projector on the ceiling, so let's make it more interesting. Fire up Geogebra, and drop some points onto the cartesian plane like so:

Now I can ask the students some questions: Are these points on a straight line? Does the fact that they are on a straight line mean that there is some connection between the x-coordinate and the y-coordinate for each point? (To which I got the reply, "There must be, or you wouldn't have asked." I didn't mind that, it was the next statement that threw me - "No, Mr D often asks weird questions"!)

Having decided that there may be a connection, the students put there heads together and came up with an answer, which then gave me the opportunity to ask how we would write that as a mathematical statement. Having decided on 'y = 2x -1', Geogebra then allowed to neatly type exactly that into the input field at the bottom of the window - the line appeared on screen passing through all the points, and the students were quite pleased with themselves.

A few more examples done the same way and the students had clearly grasped the concepts I wanted to get across. One boy asked a nice question about expressing one of our 'rules' differently (x in terms of y) which led to some useful discussion.

What I found most pleasing about this was the ease with which I was able to do what I needed. Simply being able to type in the equation as I would write it on the board made the connection all the more obvious to the students. I could have done the same thing with Geometer's SketchPad (and I still like GSP for certain things), but Geogebra seems easier and more intuitive for a lot of this type of work.

Geogebra - my students are going to be seeing a lot more of it.

Tuesday, 6 July 2010

Spam Leaking In

Lately, this blog has been targeted by spammers. To be precise, Chinese speaking spammers with Google/Blogger accounts. It appears that somewhere in China (or Singapore?), individuals are creating Google/Blogger accounts for the express purpose of being able to put spam into comments on blogs like mine that require users to have such an account in order to comment.

I know this is not Google/Blogger's fault. But it would be nice to have an option to not just reject a comment, but also flag the commenter as a suspicious account for Blogger to investigate. Maybe one day.

In the meanwhile, to my spamming 'friends', I say: STFUAPO!

Addendum: in light of the fact that spam comments have continued, and I'm tired of seeing them appear in my inbox for moderation, I've limited comments to blog members (i.e. me.) Anyone wanting to comment for now will need to email me instead.

Friday, 11 June 2010

Game: Set and Match

I love Python. Have I mentioned that before?

I learned programming first as a student teaching myself BASIC on an Apple ][. When I got to Uni, I was initiated into the ways of FORTRAN and Pascal. I got to grips with C, and later as a teacher, I became familiar with Javascript and PHP. I've even spent some time tackling Java and C++.

But is wasn't until I started seriously looking at Python as a replacement for Pascal in my teaching programs that I started to appreciate the differences between various languages and how this affects the way I program.

And I find programming in Python to be a real joy. I find it flexible and easy to read, but replete with functionality. As a language to teach to students, it fills my requirements beautifully.

I'm sure that others will prefer different languages (and I have spent a little time on Ruby, and I can see its appeal), and for various reasons. I'm well aware that performance-wise, there are many languages that execute faster than Python. I came across an example of this only the other day. Andrew Choi is a computer scientist, who is also a jazz enthusiast, like me. He's written programs to generate jazz accompaniment in MIDI. One program was originally written in Python, but then Andrew rewrote his program in OCaml and achieved a massive increase in performance.

So would I consider switching to OCaml? Have you looked at OCaml?? OCaml is what you get when you let a programming language be designed by a committee.1 I'll stick to Python.

An example of what I find so nice about Python: I posed a problem to my students the other day about looping over a list and clearing out duplicate elements so that only a single instance of any particular element remained. The students came up with a couple of ways of doing this, but their approaches, as you might expect, involved looping over the lists. But Python (typically) provides more than one way to tackle this problem.

Consider a list with duplicate elements:

>>> L = [1, 2, 3, 2, 3, 2, 2, 3, 1, 5]

Python lets you remove the dupes from this list using a single line of code:

>>> L = list(set(L))

That's it! Don't believe me? Try it for yourself.

I hadn't really looked at Python's set type before, I think mainly because the resources I've relied on to learn about (and teach) Python have made little mention of it, which is a bit odd, given how useful set operations are. (Though that may be the mathematician/database developer sides of me coming out.)

Need to match up the common elements in two lists (call them A and B)? The answer is as simple as this:

>>> common = list(set(A) & set(B))

How simple is that!

Did I mention that I love Python?

1. With apologies to Mark Twain.