Pick a starting point and let the hunter scan upward for primes p whose partner p + 2 is also prime. Each twin pair it finds is highlighted; the counter shows how dense they are in that stretch.
<p class="hint">A <b>twin prime</b> pair is two primes that differ by 2, like 11 and 13.
Pick a starting point and scan upward. The hunter sieves each range, highlights every
twin pair it finds, and reports how dense they are. Watch them thin out — yet keep
appearing.</p>
<div class="controls">
<label>Start at <input id="start" type="number" min="1" value="1"></label>
<button id="hunt" type="button">Hunt next 1000</button>
<button id="reset" type="button" class="ghost">Reset</button>
</div>
<div class="status" id="status">Press “Hunt next 1000”.</div>
<div id="pairs" class="pairs"></div>
* { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; color: #222; margin: 0; }
.hint { font-size: .9rem; color: #444; margin: 0 0 .7rem; line-height: 1.45; }
.controls { display: flex; gap: .5rem; align-items: center; flex-wrap: wrap; margin: .4rem 0; }
label { font-size: .9rem; color: #1d3557; }
input { width: 7rem; font: 600 14px system-ui, sans-serif; padding: .35rem .5rem;
border: 1px solid #cdd9e3; border-radius: 7px; }
button { font: 600 14px system-ui, sans-serif; padding: .45rem .9rem; border: 1px solid #1d3557;
background: #1d3557; color: #fff; border-radius: 8px; cursor: pointer; }
button.ghost { background: #fff; color: #1d3557; }
.status { font-size: 1rem; font-weight: 600; margin: .6rem 0; min-height: 1.4em; color: #0a7d33; }
.pairs { display: flex; flex-wrap: wrap; gap: .35rem; margin-top: .5rem; }
.pair { background: #e8eef3; color: #1d3557; border: 1px solid #cdd9e3; border-radius: 999px;
padding: .2rem .6rem; font: 600 13px ui-monospace, monospace; }
.pair b { color: #c92f3c; }
const fmt = (s, v) => s.replace(/%(\w+)%/g, (_, k) => String(v[k] ?? ''));
// Twin prime hunt. A twin pair is (p, p+2) with both prime. Whether infinitely many
// such pairs exist is the Twin Prime Conjecture — OPEN since the 1800s. Zhang (2013)
// proved primes infinitely often within a bounded gap; Maynard/Polymath got it to 246.
// Here we just sieve a range and watch the twins thin out yet never disappear.
const WINDOW = 1000;
let cursor = 1;
// Sieve of Eratosthenes up to n inclusive -> boolean[] isPrime.
function sieve(n){
const p = new Array(n + 1).fill(true);
p[0] = false; if (n >= 1) p[1] = false;
for (let i = 2; i * i <= n; i++) if (p[i])
for (let j = i * i; j <= n; j += i) p[j] = false;
return p;
}
function twinsInRange(lo, hi){
// need primality up to hi+2 so we can test the partner p+2
const isP = sieve(hi + 2);
const out = [];
for (let p = Math.max(lo, 2); p <= hi; p++)
if (isP[p] && isP[p + 2]) out.push([p, p + 2]);
return out;
}
function setStatus(t){ document.getElementById('status').textContent = t; }
function hunt(){
const lo = cursor;
const hi = cursor + WINDOW - 1;
const twins = twinsInRange(lo, hi);
const box = document.getElementById('pairs');
box.innerHTML = '';
twins.forEach(([a, b]) => {
const d = document.createElement('div');
d.className = 'pair';
d.innerHTML = '<b>' + a + '</b>, <b>' + b + '</b>';
box.appendChild(d);
});
const per = (twins.length / WINDOW * 1000).toFixed(1);
setStatus(fmt('Range %lo%–%hi%: found %length% twin pairs (%per% per 1000). They thin out, but keep appearing.', { lo: lo, hi: hi, length: twins.length, per: per }));
console.log('range', lo, '-', hi, '| twin pairs:', twins.length);
cursor = hi + 1;
}
document.getElementById('hunt').addEventListener('click', () => {
const v = parseInt(document.getElementById('start').value, 10);
if (!Number.isNaN(v) && v >= 1 && v !== 1 && cursor === 1) cursor = v;
else if (cursor === 1 && !Number.isNaN(v) && v >= 1) cursor = v;
hunt();
});
document.getElementById('reset').addEventListener('click', () => {
cursor = 1; document.getElementById('start').value = '1';
document.getElementById('pairs').innerHTML = '';
setStatus('Press “Hunt next 1000”.');
});
<p class="hint">A <b>twin prime</b> pair is two primes that differ by 2, like 11 and 13.
Pick a starting point and scan upward. The hunter sieves each range, highlights every
twin pair it finds, and reports how dense they are. Watch them thin out — yet keep
appearing.</p>
<div class="controls">
<label>Start at <input id="start" type="number" min="1" value="1"></label>
<button id="hunt" type="button">Hunt next 1000</button>
<button id="reset" type="button" class="ghost">Reset</button>
</div>
<div class="status" id="status">Press “Hunt next 1000”.</div>
<div id="pairs" class="pairs"></div>
* { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; color: #222; margin: 0; }
.hint { font-size: .9rem; color: #444; margin: 0 0 .7rem; line-height: 1.45; }
.controls { display: flex; gap: .5rem; align-items: center; flex-wrap: wrap; margin: .4rem 0; }
label { font-size: .9rem; color: #1d3557; }
input { width: 7rem; font: 600 14px system-ui, sans-serif; padding: .35rem .5rem;
border: 1px solid #cdd9e3; border-radius: 7px; }
button { font: 600 14px system-ui, sans-serif; padding: .45rem .9rem; border: 1px solid #1d3557;
background: #1d3557; color: #fff; border-radius: 8px; cursor: pointer; }
button.ghost { background: #fff; color: #1d3557; }
.status { font-size: 1rem; font-weight: 600; margin: .6rem 0; min-height: 1.4em; color: #0a7d33; }
.pairs { display: flex; flex-wrap: wrap; gap: .35rem; margin-top: .5rem; }
.pair { background: #e8eef3; color: #1d3557; border: 1px solid #cdd9e3; border-radius: 999px;
padding: .2rem .6rem; font: 600 13px ui-monospace, monospace; }
.pair b { color: #c92f3c; }
const fmt = (s, v) => s.replace(/%(\w+)%/g, (_, k) => String(v[k] ?? ''));
// Twin prime hunt. A twin pair is (p, p+2) with both prime. Whether infinitely many
// such pairs exist is the Twin Prime Conjecture — OPEN since the 1800s. Zhang (2013)
// proved primes infinitely often within a bounded gap; Maynard/Polymath got it to 246.
// Here we just sieve a range and watch the twins thin out yet never disappear.
const WINDOW = 1000;
let cursor = 1;
// Sieve of Eratosthenes up to n inclusive -> boolean[] isPrime.
function sieve(n){
const p = new Array(n + 1).fill(true);
p[0] = false; if (n >= 1) p[1] = false;
for (let i = 2; i * i <= n; i++) if (p[i])
for (let j = i * i; j <= n; j += i) p[j] = false;
return p;
}
function twinsInRange(lo, hi){
// need primality up to hi+2 so we can test the partner p+2
const isP = sieve(hi + 2);
const out = [];
for (let p = Math.max(lo, 2); p <= hi; p++)
if (isP[p] && isP[p + 2]) out.push([p, p + 2]);
return out;
}
function setStatus(t){ document.getElementById('status').textContent = t; }
function hunt(){
const lo = cursor;
const hi = cursor + WINDOW - 1;
const twins = twinsInRange(lo, hi);
const box = document.getElementById('pairs');
box.innerHTML = '';
twins.forEach(([a, b]) => {
const d = document.createElement('div');
d.className = 'pair';
d.innerHTML = '<b>' + a + '</b>, <b>' + b + '</b>';
box.appendChild(d);
});
const per = (twins.length / WINDOW * 1000).toFixed(1);
setStatus(fmt('Range %lo%–%hi%: found %length% twin pairs (%per% per 1000). They thin out, but keep appearing.', { lo: lo, hi: hi, length: twins.length, per: per }));
console.log('range', lo, '-', hi, '| twin pairs:', twins.length);
cursor = hi + 1;
}
document.getElementById('hunt').addEventListener('click', () => {
const v = parseInt(document.getElementById('start').value, 10);
if (!Number.isNaN(v) && v >= 1 && v !== 1 && cursor === 1) cursor = v;
else if (cursor === 1 && !Number.isNaN(v) && v >= 1) cursor = v;
hunt();
});
document.getElementById('reset').addEventListener('click', () => {
cursor = 1; document.getElementById('start').value = '1';
document.getElementById('pairs').innerHTML = '';
setStatus('Press “Hunt next 1000”.');
});
Notice two things at once. The twins thin out — higher ranges hold fewer of them per thousand numbers. And yet they keep appearing, range after range, with no sign of a final pair. That is exactly the tension the conjecture lives in: the evidence screams "infinitely many," but evidence is not a proof.
Comments
Loading comments...