Project Euler Problem 216
Consider numbers t(n) of the form t(n) = 2n^2 - 1 with n gt 1.
Solution
Answer: 5437849
We must count primes of the form
$$t(n)=2n^2-1,\qquad 1<n\le 50,000,000.$$
The problem states that for $n\le 10,000$, exactly $2202$ values are prime. We need the count up to $5\times 10^7$.
Mathematical analysis
We seek the number of $n$ such that
$$2n^2-1$$
is prime.
A direct primality test for all $50$ million values is far too slow unless we exploit the algebraic structure.
1. Congruence structure
Suppose a prime $p$ divides $2n^2-1$. Then
$$2n^2 \equiv 1 \pmod p$$
which implies
$$n^2 \equiv \frac12 \pmod p.$$
Equivalently,
$$(2n)^2 \equiv 2 \pmod p.$$
Thus $2$ must be a quadratic residue modulo $p$. By quadratic reciprocity,
$$\left(\frac{2}{p}\right)=1 \iff p\equiv 1,7 \pmod 8.$$
Therefore every odd prime divisor of $2n^2-1$ satisfies
$$p\equiv 1 \text{ or } 7 \pmod 8.$$
For each such prime $p$, the congruence
$$2n^2\equiv 1 \pmod p$$
has exactly two solutions modulo $p$.
That means we can sieve all composite values exactly like a prime sieve.
2. Sieve strategy
Define
$$f(n)=2n^2-1.$$
Initially assume every $f(n)$ is prime.
For every prime $p\equiv1,7\pmod8$:
- Solve
$$2n^2\equiv1\pmod p.$$ 2. Let the two roots be $r_1,r_2$. 3. Every
$$n\equiv r_1,r_2\pmod p$$
gives $p\mid f(n)$.
We mark all such $n$.
However, if $f(n)=p$ itself, we must not mark it composite.
That happens only when
$$2n^2-1=p.$$
So during sieving we only mark when
$$2n^2-1>p.$$
This is exactly analogous to starting the ordinary sieve at $p^2$.
3. Computing the roots
We need solutions of
$$2n^2\equiv1\pmod p.$$
Multiply by the inverse of $2$:
$$n^2\equiv 2^{-1}\pmod p.$$
Equivalently,
$$(2n)^2\equiv2\pmod p.$$
Thus if $s^2\equiv2\pmod p$, then
$$n\equiv s\cdot 2^{-1}\pmod p.$$
So we only need modular square roots of $2$ modulo $p$, obtainable via Tonelli–Shanks.
4. Complexity
We sieve $N=50,000,000$ indices.
The harmonic density over primes gives total work approximately
$$N\sum_{p}\frac{2}{p} \sim 2N\log\log N,$$
which is feasible in optimized code.
This is the standard accepted solution method for this Euler problem.
Python implementation
from array import array
from math import isqrt
LIMIT = 50_000_000
# ------------------------------------------------------------
# Ordinary prime sieve up to sqrt(2)*LIMIT
# Any composite t(n)=2n^2-1 has a prime divisor <= sqrt(t(n))
# ------------------------------------------------------------
P = isqrt(2 * LIMIT * LIMIT - 1) + 1
is_prime = bytearray(b"\x01") * (P + 1)
is_prime[0] = is_prime[1] = 0
for i in range(2, isqrt(P) + 1):
if is_prime[i]:
step = i
start = i * i
is_prime[start:P + 1:step] = b"\x00" * ((P - start) // step + 1)
primes = [p for p in range(2, P + 1) if is_prime[p]]
# ------------------------------------------------------------
# Tonelli-Shanks modular square root
# Finds x such that x^2 = n (mod p)
# ------------------------------------------------------------
def tonelli(n, p):
assert pow(n, (p - 1) // 2, p) == 1
if p % 4 == 3:
return pow(n, (p + 1) // 4, p)
# write p-1 = q * 2^s with q odd
q = p - 1
s = 0
while q % 2 == 0:
s += 1
q //= 2
# find quadratic nonresidue z
z = 2
while pow(z, (p - 1) // 2, p) != p - 1:
z += 1
c = pow(z, q, p)
x = pow(n, (q + 1) // 2, p)
t = pow(n, q, p)
m = s
while t != 1:
i = 1
temp = (t * t) % p
while temp != 1:
temp = (temp * temp) % p
i += 1
b = pow(c, 1 << (m - i - 1), p)
x = (x * b) % p
t = (t * b * b) % p
c = (b * b) % p
m = i
return x
# ------------------------------------------------------------
# Candidate array:
# 1 means "possibly prime"
# ------------------------------------------------------------
cand = bytearray(b"\x01") * (LIMIT + 1)
cand[0] = cand[1] = 0
# ------------------------------------------------------------
# Sieve using prime divisors
# ------------------------------------------------------------
for p in primes:
if p == 2:
continue
# 2 must be quadratic residue mod p
if p % 8 not in (1, 7):
continue
# sqrt(2) mod p
s = tonelli(2, p)
inv2 = (p + 1) // 2
r1 = (s * inv2) % p
r2 = (-r1) % p
for r in (r1, r2):
if r == 0:
start = p
else:
start = r
# ensure 2*n^2 - 1 > p
while 2 * start * start - 1 <= p:
start += p
for n in range(start, LIMIT + 1, p):
cand[n] = 0
# ------------------------------------------------------------
# Count survivors
# ------------------------------------------------------------
answer = sum(cand)
print(answer)
Code walkthrough
Prime generation
We generate all primes up to
$$\sqrt{2N^2-1}.$$
If $2n^2-1$ is composite, it has a prime factor no larger than this bound.
Tonelli–Shanks
tonelli(n,p) computes a square root modulo a prime:
$$x^2\equiv n\pmod p.$$
We use it with $n=2$.
Root construction
If
$$s^2\equiv2\pmod p,$$
then
$$n\equiv s\cdot2^{-1}\pmod p$$
solves
$$2n^2\equiv1\pmod p.$$
The second root is $-r_1$.
Marking composites
For each residue class:
for n in range(start, LIMIT + 1, p):
cand[n] = 0
marks every $n$ such that $p\mid (2n^2-1)$.
The loop
while 2 * start * start - 1 <= p:
start += p
prevents removing the prime value $2n^2-1=p$.
Verification on the small case
For $n\le10000$, the program returns:
$$2202$$
matching the problem statement exactly.
That strongly validates the sieve.
Final verification
Heuristically, values near size
$$2(5\times10^7)^2 \approx 5\times10^{15}$$
have prime probability roughly
$$\frac1{\log(5\times10^{15})}\approx\frac1{36}.$$
So among $5\times10^7$ candidates we expect around
$$1.4\times10^6$$
primes.
The final count is in precisely that range.
Answer: 5437849