Friday, 5 December, 2014

Recently, after being awake for longer than I should have, I started thinking about methods of remembering the number of days in each month of the year. There is a rhyme for it, and a way to count on your knuckles, but these didn’t satisfy me. I wondered if there was a mathematical formula for the problem, and upon not immediately finding one, I challenged myself to create one.

In other words, the challenge was this: find a function f , such that f(x) is equal to the number of days in month x , represented by the integers 1 through 12. Or, as a table of values:

x 1 2 3 4 5 6 7 8 9 10 11 12 f(x) 31 28 31 30 31 30 31 31 30 31 30 31

If you want to give this challenge a go before reading my solution, now is your chance. If you’d rather see my complete solution right away, scroll to the bottom of the page. What follows is my process for solving the problem.

Firstly, here’s a quick refresher on two operations I found vital to solving the problem: floor division and modulo.

Floor division is the operation performed by many programming languages when dividing two integer numbers, that is, the result of the division is truncated to the integer part. I will represent floor division as ⌊ a ⁄ b ⌋, for example:

⌊5⁄ 3 ⌋ = 1

Modulo is an operation that results in the remainder of a division. It is represented in many programming languages with the % operator. I will represent it as “ a mod b ”, for example:

3 mod 2 = 1

Note that modulo has the same precedence as division.

The Basics

With those tools in mind, let’s get a basic pattern going. Months usually alternate between lengths of 30 and 31 days. We can use x mod 2 to get an alternating pattern of 1 and 0, then just add our constant base number of days:

f(x) = 30 + x mod 2

x 1 2 3 4 5 6 7 8 9 10 11 12 f(x) 31 30 31 30 31 30 31 30 31 30 31 30

That’s a pretty good start! We’ve already got January and March through July done. February is its own special problem we’ll deal with later. The problem after July is that the pattern should skip one, and the rest of the months should follow the alternating pattern inversely.

To obtain an inverse pattern of alternating 0 and 1, we can add 1 to our dividend:

f(x) = 30 + ( x + 1) mod 2

x 1 2 3 4 5 6 7 8 9 10 11 12 f(x) 30 31 30 31 30 31 30 31 30 31 30 31

Now we have August through December right, but the rest of the year is wrong as expected. Let’s see how we can combine combine our two formulas.

Masking

What we need here is basically a piece-wise function, but that’s just no fun. This got me thinking of other ways to use a part of a function only over a certain domain.

I figured the easiest way to do this would be to find an expression equal to 1 over the desired domain and 0 otherwise. Multiplying a term by this expression will result in the term being cancelled out outside its domain. I’ve called this “masking,” since it involves creating a sort of bit-mask.

To mask the latter piece of our function, we need an expression equal to 1 where 8 ≤ x ≤ 12. Floor division by 8 is perfect for this, since all our values are less than 16.

x 1 2 3 4 5 6 7 8 9 10 11 12 ⌊x⁄ 8 ⌋ 0 0 0 0 0 0 0 1 1 1 1 1

Now if we substitute this expression in our x + 1 dividend, we can invert the pattern using our mask:

f(x) = 30 + ( x + ⌊ x ⁄ 8 ⌋) mod 2

x 1 2 3 4 5 6 7 8 9 10 11 12 f(x) 31 30 31 30 31 30 31 31 30 31 30 31

Woot! Everything is correct except February. What a surprise.

February

Every month has either 30 or 31 days, but February has 28 (leap years are out of scope). February currently has 30 days according to our formula, so an expression equal to 2 when x = 2 would be ideal for subtraction.

The best I could come up with was 2 mod x , which gives us a sort of mask over every month after February.

x 1 2 3 4 5 6 7 8 9 10 11 12 2 mod x 0 0 2 2 2 2 2 2 2 2 2 2

With this, we’ll need to change our base constant to 28 so that adding 2 to the rest of the months will still be correct.

f(x) = 28 + ( x + ⌊ x ⁄ 8 ⌋) mod 2 + 2 mod x

x 1 2 3 4 5 6 7 8 9 10 11 12 f(x) 29 28 31 30 31 30 31 31 30 31 30 31

Unfortunately, January is now 2 days short. Luckily, finding an expression that will apply to only the first month is easy: floored inverse of x . Now just multiply that by 2 and we get the final formula:

f(x) = 28 + ( x + ⌊ x ⁄ 8 ⌋) mod 2 + 2 mod x + 2 ⌊1⁄ x ⌋

x 1 2 3 4 5 6 7 8 9 10 11 12 f(x) 31 28 31 30 31 30 31 31 30 31 30 31

Conclusion

2014-12-06 : Hello, Internet. This is tongue-in-cheek. Why would anyone use this?

There you have it, a formula for the number of days in each month using simple arithmetic. So next time you find yourself wondering how many days are in September, just remember to apply f (9). For ease of use, here’s a JavaScript one-liner: