You may have seen the memes going around about fun ways to program the
straightforward function isEven() which returns TRUE if the input is even,
and FALSE otherwise. I had a play with this and it turned into enough for a
blog post, and a nice walk through some features of R.

The ‘traditional’ way to check if an integer is even is to check if it is
divisible by 2. This can be achieved with the modulo operator %% which
gives the remainder after dividing by another number. For example, 5 modulo 2
or 5 %% 2 gives 1 because 2 goes into 5 twice with 1 leftover. If a number x is
even, it is an exact multiple of 2, and so x %% 2 == 0.

5 %% 2

## [1] 1

6 %% 2

## [1] 0

A function which tests values of x for this property could be written as

## 1
isEven

The == operation checks that the left side is equal to the right side (but not
necessarily identical, e.g. the classes can be different) and returns either TRUE
or FALSE (or NA, but that’s not an issue for the cases we’re looking at here).
I’ve also relied on the fact that the result of the last statement in a function
body is used as the return value if no explicit return() is used.

Confirming that this works is as easy as trying some values. It’s always good to
check that your function produces results you expect. It’s also a good idea to try
some odd values to ensure you don’t hit edge-cases.

isEven(0)

## [1] TRUE

isEven(3)

## [1] FALSE

isEven(4)

## [1] TRUE

isEven(-1)

## [1] FALSE

isEven(-6)

## [1] TRUE

In the process of playing with this function I refined how I tested my code. I started
with a set of confirming evaluations like above. Then I wanted to confirm that they
actually gave the results I expect, so I refined it to

test_isEven

Now I just had one function to call which confirmed that all these tests gave
the expected results. Once I had explained this layout to myself with the word
‘expected’, I realised what I actually wanted was a test suite, and testthat
is a great candidate for that. Refactoring the above into a series of expectations
might look like

library(testthat)
test_isEven

Now I can test any implementation of isEven() with just one function call, and if
one of the expectations fails I’ll know which it is. Running this with the aboveisEven() produces no output, so the tests succeeded

test_isEven()

The ‘no output’ might be concerning, so we can also run a negative control to make
sure it breaks when things are broken. Let’s break the isEven() by reversing the
test

So, we can trust that if we make a mistake or don’t implement this properly,
we’ll know. Typically a function you write would have a lot more safety checking,
such as ensuring that we actually passed a value, and that it’s an integer, but for
the sake of this post I’m going to assume that these are both guaranteed to be true.

This version of isEven() is simple and it works, but that’s not what the internet
wants – a common challenge is to make a version of isEven() which doesn’t use
modulo. Now we need to think a little more, but we can at least check any
implementation with our tests.

I came up with a few, both from borrowing from other solutions and on my own. Let’s see…

If the last digit is any of 0, 2, 4, 6, or 8, then it’s an even number

## 2
isEven

With that same idea, if the least significant bit (binary) is unset then it’s even

## 3
isEven

Continuing down the bitwise path, if we can shift left and right and get back to
the original number, then it’s even

## 4
isEven

If we alternate FALSE and TRUE counting from 0 to x then we get our answer

## 5
isEven

We could do the same thing with recursion

## 6
isEven

Not quite using modulo, integer division by 2, doubled, should
return the original value

## 7
isEven

Similarly, the result of regular division cast to integer, doubled, should
return the original value

## 7a
isEven

If we start from a number and count towards 0 by twos then we will hit 0
if the number is even

## 8
isEven

We can write that a bit simpler if we only use the absolute value of x

## 8a (abs version)
isEven

Exploiting mathematical properties, we know that -1 to any even power returns 1

## 9
isEven

The relationship \[\cos(2x) = -\cos(x)\] can also be exploited

## 10
isEven

Now for some more R-specific solutions… R rounds towards even integers, and
we can exploit that

## 11
isEven

We can create a vector of ‘every other integer’ and check whether a value is in
there

## 12
isEven

Creating a vector of TRUE and FALSE we can extract the element corresponding to
a value

## 13
isEven

Then, starting to get really absurd, we could solve the equation \[2n = x\] which
will have an integer n if x is even

## 14
isEven

And, lastly, for the truly absurd, we can use the fact that “zero” and “eight” are
the only single digits written as English words with an “e”. This requires a
couple of extra packages, but can be done.