Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Quadratic Primes

Euler discovered the remarkable quadratic formula:

\begin{align} n^{2} + n + 41 \end{align}

It turns out that the formula will produce \(40\) primes for the consecutive integer values \(0 \leq n \leq 39\). However, when \(n = 40, 40^{2} + 40 + 41 = 40(40 + 1) + 41\) is divisible by \(41\), and certainly when \(n = 41, 41^{2} + 41 + 41\) is clearly divisible by \(41\).

The incredible formula \(n^{2} - 79n + 1601\) was discovered, which produces \(80\) primes for the consecutive values \(0 \leq n \leq 79\). The product of the coefficients, \(-79\) and \(1601\), is \(-126479\).

Considering quadratics of the form:

     \(n^2 + an + b\), where \(|a| < 1000\) and \(|b| \leq 1000\)

     e.g. \(|11| = 11\) and \(|-4| = 4\)

Find the product of the coefficients, \(a\) and \(b\), for the quadratic expression that produces the maximum number of primes for consecutive values of \(n\), starting with \(n = 0\) .

Solution

That’s a long problem description for a relatively easy task. It looks daunting, but in reality it’s quite simple.

We need to find a and b for which the consecutive values of n produce the largest amount of primes. Because the constraints are relatively low, we don’t need to optimize much, a brute-force solution will work just fine.

Oh well, maybe let’s just do one! Take a look at the formula here: \(n^2 + an + b\)

Try substituting n and think if you can spot a certain property of a or b that can limit what we need to check.

Can you see it? Hint, try: n = 0

If the n = 0, then we’re left with just b. It means that if we’re looking for consecutive values of primes, the first prime must be a number when n = 0, and in the formula there’s just b. So, b must be a prime!

import EulerHelper.naiveIsPrime

object Euler027 extends EulerApp {

  override def execute(): Int = {
    val coefficients = for {
      a <- -999 until 1000
      b <- 2 to 1000 if b.naiveIsPrime
    } yield (a, b)

    val (a, b) = coefficients.maxBy { case (a, b) =>
      consecutivePrimes(a, b)
    }

    a * b
  }

  private def consecutivePrimes(a: Int, b: Int): Int =
    Iterator.from(0).takeWhile { n =>
      (n * n + n * a + b).naiveIsPrime
    }.length

}

Final notes

The solution works relatively fast. If we had longer prime sequences, this part could’ve been a bit troublesome:

Iterator.from(0).takeWhile { n =>
  (n * n + n * a + b).naiveIsPrime
}.length

As you can see, we check .length at the very end, meaning that all the primes are collected to a list. That’s not what we need, right? To keep it clean, one could write a small helper like this one:

extension[A] (i: Iterator[A]) {
  private def countWhile(f: A => Boolean): Int = {
    var count = 0
    while (i.hasNext && f(i.next())) {
      count += 1
    }
    count
  }
}