I'm a web developer specialising in front-end solutions combining clean coding with intuitive user interfaces and striking design approaches. I'm moving into the sector from a background in graphic design. I'm looking for junior web development roles where I can contribute from the outset with my strong creative problem solving skills, while also building my knowledge and experience of the sector. You can view some of my sample projects here, and read more about my work on my coding blog.

A prime year

05 Jan 2021

My friend Lucie pointed out earlier this week that 2021 is a rare year whose value is the product of two consecutive primes. Apparently this hasn’t happened since 1763 and won’t happen again until 2491. Clearly this has great cosmological significance, so I decided to check the figures in case of any awkward mistakes.

In the code below the function checkPrime(n) generates an array of prime numbers up to some maximum value. The primeMultiples() function works through this array and logging every possible value for n * (n+1).

let primes = [];

function findPrimes(n) {
  for (let i = 2; i <= n; i++) {
    let isPrime = true;
    for (let j = 2; j < i; j++) {
      if (i % j === 0) {
        isPrime = false;
        continue;
      }
    }
    if (isPrime) {
      primes.push(i);
    }
  }
  console.log(primes);
}

findPrimes(100);

function primeMultiples() {
 for (let n = 0; n < primes.length - 1; n++) {
    console.log(primes[n] * primes[n + 1]);
  }
}

primeMultiples();

Comparing against this output we can see that Lucie’s initial dates were correct! Not a hugely difficult problem to solve, but it got me thinking about methods for generating primes. In my function I used trial division, a pretty naive approach where every number in the list of numbers [2,3,4,…n] is checked against every number below it to see if it will factorise. For each number, a variable isPrime is generated; this starts off true, and flips to false if a factor is discovered. If a number survives every check against possible factors, it stays true and gets logged to the console.

This method is rigourous but slow, so I had a go at making an alternative prime generator based on the “sieve of Eratosthenes” algorithm, which takes a more efficient approach.

function sievePrimes(n){

let startArray = [];
let limit = Math.sqrt(n)
let primes = [];

for (let i = 0; i < n; i++) {
    array.push(true);
  }
  for (let i = 2; i <= limit; i++) {
        if (array[i]) {
            for (let j = i * i; j < n; j += i) {
                array[j] = false;
            }
        }
    }
 for (let i = 2; i < n; i++) {
       if(array[i]) {
           primes.push(i);
        }
    }
    return primes;


}

console.log(sievePrimes(100));

Like before, sievePrimes() initially treats all numbers as potential primes: we start off with an empty array and generate a true value for every number in our list [2,3,4,…n]. Starting with our lowest value (2), we generate every possible multiple of (4,6,8…) and mark it false since we know 2 is a factor. We do the same with each subsequent number all the way up to n, quickly whittling down the field of possible prime candidates. The wikipedia page on this alogorithm has a great animation to illustrate how this works.

As an additional timesaver, the inner loop of this function starts with the square of each value; since we’re evaluating every possible multiple of each value, we know that by the time we get to 5 (for example), that 5+5=10 will already have been evaluated as 2+2+2+2+2 and 5+5+5=15 will have been evaluated as 3+3+3 and earmarked as non-prime at an earlier iteration of the function: there’s no reason to start our checks before we get to 5*5=25.

A similar logic allows us to use limit = Math.sqrt(n) to terminate the inner loop. Clearly sqrt(n)*sqrt(n) is the biggest possible pair of factors we will find for a number in our range, so there’s no need to run checks using any value larger than this.

Working on these functions has highlighted a couple of things I’ve already discovered while learning coding. Most problems have multiple solutions, and figuring out how to slice the cake in many ways can be really useful for learning and development. However, the simple solution can sometimes be just as valuable as the optimised solution in terms of effort versus results and time saved.