Question
Euler published the remarkable quadratic formula:
n^2 + n + 41
It turns out that the formula will produce 40 primes for the consecutive values n = 0 to 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.
Using computers, the incredible formula n^2 - 79n + 1601 was discovered, which produces 80 primes for the consecutive values n = 0 to 79. The product of the coefficients, 79 and 1601, is 126479.
Considering quadratics of the form:
n^2 + an + b, \text{ where } |a| \lt 1000 \text{ and } |b| \lt 1000
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.
Haskell
import Data.Function (on)
import Data.List (maximumBy)
isPrime :: Int -> Bool
| n < 1 = False
isPrime n | otherwise = not $ or [n `rem` x == 0 | x <- [2..floor $ sqrt $ fromIntegral n]]
coefficients :: [(Int, Int)]
= [(a, b) | a <- [-999..999], b <- filter isPrime [0..999]]
coefficients
primesProduced :: (Int, Int) -> Int
= length $ takeWhile isPrime [n^2 + a*n + b | n <- [0..]]
primesProduced (a, b)
main :: IO ()
= print $ uncurry (*) $ maximumBy (compare `on` primesProduced) coefficients main
$ ghc -O2 -o quadratic-primes quadratic-primes.hs
$ time ./quadratic-primes
real 0m2.612s
user 0m2.604s
sys 0m0.008s
Python
#!/usr/bin/env python
from collections import defaultdict
from itertools import product
from operator import mul
import math
from functools import reduce
def factorize(n):
if n < 1:
raise ValueError('fact() argument should be >= 1')
if n == 1:
return [] # special case
= []
res # iterate over all even numbers first.
while n % 2 == 0:
2)
res.append(//= 2
n # try odd numbers up to sqrt(n)
= math.sqrt(n+1)
limit = 3
i while i <= limit:
if n % i == 0:
res.append(i)//= i
n = math.sqrt(n+i)
limit else:
+= 2
i if n != 1:
res.append(n)return res
def num_divisors(n):
= sorted(factorize(n))
factors = defaultdict(int)
histogram for factor in factors:
+= 1
histogram[factor] # number of divisors is equal to product of
# incremented exponents of prime factors
from operator import mul
try:
return reduce(mul, [exponent + 1 for exponent in list(histogram.values())])
except:
return 1
def num_primes(formula):
= 0
num for n in range(1000):
= formula(n)
res if res < 1 or not is_prime(res):
return num
else:
+= 1
num
def is_prime(num):
if num_divisors(num) == 2 and num > 1:
return True
else:
return False
def main():
= 0
most = (0, 0)
best for a, b in product(list(range(-999,1000)), list(range(-999, 1000))):
= lambda n: n**2 + a*n + b
formula = num_primes(formula)
num if num > most:
= num
most = (a, b)
best print(mul(*best))
if __name__ == "__main__":
main()
$ time python3 quadratic-primes.py
real 0m18.794s
user 0m18.777s
sys 0m0.016s
Ruby
#!/usr/bin/env ruby
require 'mathn'
puts (-999..999).to_a.product((-999..999).to_a).map { |a, b|
[(0..100).take_while { |n| (n**2 + a*n + b).prime? }.count, a * b]
}.max[1]
$ time ruby quadratic-primes.rb
real 0m5.754s
user 0m5.612s
sys 0m0.142s
Rust
fn is_prime(n: i64) -> bool {
if n < 1 {
return false;
}
let max = (n as f64).sqrt() as i64;
for d in 2..max {
if n % d == 0 {
return false;
}
}
true
}
fn main() {
let mut best = (0, 0);
let mut best_count = 0;
let bs = (0..1000).filter(|&b| is_prime(b)).collect::<Vec<_>>();
for a in -999..1000 {
for &b in &bs {
let count = (0..)
.take_while(|n| is_prime(n * n + a * n + b))
.map(|_| 1)
.sum::<i64>();
if count > best_count {
= (a, b);
best = count;
best_count }
}
}
println!("{}", best.0 * best.1);
}
$ rustc -C target-cpu=native -C opt-level=3 -o quadratic quadratic.rs
$ time ./quadratic
real 0m0.042s
user 0m0.042s
sys 0m0.000s