Prime Pairs
A twin prime pair is a pair of primes (p, p+2). More generally, a prime pair with gap g is (p, p+g) where both are prime. Compute pi_2(N) = |{p <= N: p and p+2 are both prime}| for a given bound N.
Problem Statement
This archive keeps the full statement, math, and original media on the page.
Let \(D(n)\) be the \(n\)-th positive integer that has the sum of its digits a prime.
For example, \(D(61) = 157\) and \(D(10^8) = 403539364\).
Find \(D(10^{16})\).
Problem 845: Prime Pairs
Mathematical Analysis
The Twin Prime Counting Function
Definition. .
The first twin prime pairs are:
Brun’s Theorem
Theorem (Brun, 1919). The sum of reciprocals of twin primes converges:
This contrasts with for all primes, and implies twin primes are “sparse” relative to all primes.
Hardy-Littlewood Conjecture
Conjecture (1st Hardy-Littlewood). As :
where is the twin prime constant.
Sieve Methods
Theorem (Sieve of Eratosthenes). To find all primes up to , sieve by primes up to . The segmented sieve processes blocks of size using small primes, achieving time and space.
Algorithm for twin primes: Apply the sieve, then scan for consecutive primes with gap 2.
Concrete Values
| Hardy-Littlewood estimate | |||
|---|---|---|---|
| 25 | 8 | 8.2 | |
| 168 | 35 | 32.7 | |
| 1229 | 205 | 214.2 | |
| 9592 | 1224 | 1249 | |
| 78498 | 8169 | 8248 | |
| 664579 | 58980 | 58754 | |
| 5761455 | 440312 | 440368 |
Chen’s Theorem
Theorem (Chen, 1973). There are infinitely many primes such that is either prime or a semiprime (product of two primes).
Connection to Goldbach
The twin prime conjecture is equivalent to: there are infinitely many integers such that both and are prime. This is a special case of Polignac’s conjecture ().
Theorem (Zhang, 2013; Maynard, 2014). There exist infinitely many pairs of primes with bounded gap. Currently the best bound is .
Complexity Analysis
- Basic sieve: time, space.
- Segmented sieve: time, space.
- Counting only: No need to store all primes; just count pairs while sieving.
The Green-Tao Theorem
Theorem (Green-Tao, 2008). The primes contain arbitrarily long arithmetic progressions.
This is a generalization of the twin prime problem to longer patterns. While twin primes have gap 2 (the shortest possible non-trivial gap), the Green-Tao theorem shows that primes exhibit large-scale regularity.
Sieve of Sundaram
An alternative to Eratosthenes for generating primes: remove all numbers of the form for , then for remaining are the odd primes.
Brun’s Constant Computation
The twin prime constant has been computed to high precision. The partial sums converge slowly:
| Upper limit | |
|---|---|
| 1.518 | |
| 1.672 | |
| 1.759 | |
| 1.806 | |
| 1.870 |
Implementation Note: Wheel Factorization
Sieve efficiency can be improved by wheel factorization: pre-eliminate multiples of 2, 3, 5 (and possibly 7), reducing the sieve array to of its naive size. This gives a constant-factor improvement of roughly .
Relationship to Goldbach’s Conjecture
Every even number is conjectured to be the sum of two primes (Goldbach). The density of twin primes determines how often can be represented as for twin prime , connecting twin primes to additive problems.
Answer
Code
Each problem page includes the exact C++ and Python source files from the local archive.
#include <bits/stdc++.h>
using namespace std;
/*
* Problem 845: Prime Pairs
*
* Count twin primes (p, p+2) with p <= N.
* Uses sieve of Eratosthenes.
*/
const int MAXN = 10000001;
bool sieve[MAXN + 2];
int count_twin_primes(int N) {
fill(sieve, sieve + N + 3, true);
sieve[0] = sieve[1] = false;
for (int i = 2; (long long)i * i <= N + 2; i++) {
if (sieve[i]) {
for (int j = i * i; j <= N + 2; j += i)
sieve[j] = false;
}
}
int count = 0;
for (int p = 2; p <= N; p++) {
if (sieve[p] && sieve[p + 2])
count++;
}
return count;
}
int main() {
// Verify known values
assert(count_twin_primes(100) == 8);
assert(count_twin_primes(1000) == 35);
assert(count_twin_primes(10000) == 205);
int ans = count_twin_primes(10000000);
cout << ans << endl; // 58980
return 0;
}
"""
Problem 845: Prime Pairs
Count twin primes up to N using sieve methods.
pi_2(N) = |{p <= N : p and p+2 both prime}|
"""
from math import isqrt, log
# --- Method 1: Basic sieve + scan ---
def twin_primes_sieve(N: int):
"""Return (count of twin prime pairs, list of twin primes) up to N."""
sieve = [True] * (N + 3)
sieve[0] = sieve[1] = False
for i in range(2, isqrt(N + 2) + 1):
if sieve[i]:
for j in range(i*i, N + 3, i):
sieve[j] = False
twins = []
for p in range(2, N + 1):
if sieve[p] and p + 2 <= N + 2 and sieve[p + 2]:
twins.append(p)
return len(twins), twins
# --- Method 2: Segmented sieve ---
def twin_primes_segmented(N: int):
"""Count twin primes using segmented sieve."""
limit = isqrt(N + 2) + 1
# Small primes
small_sieve = [True] * (limit + 1)
small_sieve[0] = small_sieve[1] = False
for i in range(2, isqrt(limit) + 1):
if small_sieve[i]:
for j in range(i*i, limit + 1, i):
small_sieve[j] = False
small_primes = [i for i in range(2, limit + 1) if small_sieve[i]]
count = 0
delta = max(limit, 1000)
prev_last_prime = False # whether N-1 of previous block was prime
for lo in range(0, N + 3, delta):
hi = min(lo + delta, N + 3)
seg = [True] * (hi - lo)
if lo == 0:
if hi > 0: seg[0] = False
if hi > 1: seg[1] = False
for p in small_primes:
start = max(p * p, ((lo + p - 1) // p) * p)
for j in range(start, hi, p):
seg[j - lo] = False
for i in range(hi - lo):
actual = lo + i
if actual < 2 or actual > N:
continue
if seg[i] and actual + 2 <= N + 2:
# Check if actual + 2 is prime
idx2 = actual + 2 - lo
if 0 <= idx2 < len(seg) and seg[idx2]:
count += 1
# Handle cross-boundary case would need extra logic
return count
# --- Method 3: Direct primality check (brute force for small N) ---
def is_prime(n):
if n < 2: return False
if n < 4: return True
if n % 2 == 0 or n % 3 == 0: return False
i = 5
while i * i <= n:
if n % i == 0 or n % (i + 2) == 0:
return False
i += 6
return True
def twin_primes_brute(N: int):
return sum(1 for p in range(2, N + 1) if is_prime(p) and is_prime(p + 2))
# --- Verify ---
for N in [10, 100, 1000, 10000]:
c1, _ = twin_primes_sieve(N)
c3 = twin_primes_brute(N)
assert c1 == c3, f"N={N}: sieve={c1}, brute={c3}"
print("Verification passed!")
count, twins = twin_primes_sieve(10**7)
print(f"pi_2(10^7) = {count}")
# Hardy-Littlewood estimate
C2 = 0.66016
def hl_estimate(N):
return 2 * C2 * N / (log(N))**2