Pick any number and the tool below adds up its proper divisors. If the sum lands exactly on the number, it is perfect; less and it is deficient, more and it is abundant. Perfect numbers are the knife's edge between the two.
<p class="hint">A <b>perfect</b> number equals the sum of its proper divisors (every divisor except itself). Type a number to test it, or generate an even perfect number from a Mersenne prime exponent.</p>
<div class="row">
<input id="num" type="number" min="1" value="28" />
<button id="test" type="button">Sum the divisors</button>
</div>
<div class="status" id="status">28 = 1 + 2 + 4 + 7 + 14 = 28 — perfect!</div>
<div class="gen">
<label for="p">Mersenne exponent p:</label>
<select id="p">
<option value="2">2</option>
<option value="3" selected>3</option>
<option value="5">5</option>
<option value="7">7</option>
<option value="11">11</option>
<option value="13">13</option>
</select>
<button id="make" type="button" class="ghost">Build 2ᵖ⁻¹(2ᵖ−1)</button>
</div>
<div class="status2" id="status2"></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 .8rem; line-height: 1.45; }
.row, .gen { display: flex; gap: .5rem; align-items: center; flex-wrap: wrap; margin: .5rem 0; }
.gen label { font-size: .9rem; color: #1d3557; font-weight: 600; }
input, select { font: 600 15px system-ui, sans-serif; padding: .4rem .6rem; border: 1px solid #adb1b8;
border-radius: 8px; }
input { width: 130px; }
.status, .status2 { font-size: 1rem; font-weight: 600; margin: .5rem 0; min-height: 1.4em; line-height: 1.4; }
.status.ok, .status2.ok { color: #0a7d33; }
.status.def { color: #1d6fb8; }
.status.ab { color: #c97a16; }
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; }
code { background: #eef2f6; padding: .1rem .35rem; border-radius: 5px; font-size: .92em; }
const fmt = (s, v) => s.replace(/%(\w+)%/g, (_, k) => String(v[k] ?? ''));
// A perfect number equals the sum of its proper divisors: 6 = 1+2+3, 28 = 1+2+4+7+14.
// Less than the number => deficient; more => abundant; exactly equal => perfect.
// Even perfect numbers are EXACTLY 2^(p-1)*(2^p - 1) where 2^p - 1 is a Mersenne prime
// (Euclid-Euler theorem). Whether any ODD perfect number exists is still OPEN.
function properDivisors(n){
const ds = [];
for(let d = 1; d <= n / 2; d++){ if(n % d === 0) ds.push(d); }
return ds;
}
function isPrime(n){
if(n < 2) return false;
for(let d = 2; d * d <= n; d++){ if(n % d === 0) return false; }
return true;
}
function setStatus(t, cls){ const s = document.getElementById('status'); s.innerHTML = t; s.className = 'status ' + cls; }
function test(){
const n = Math.floor(Number(document.getElementById('num').value));
if(!Number.isFinite(n) || n < 1){ setStatus('Enter a whole number ≥ 1.', ''); return; }
const ds = properDivisors(n);
const sum = ds.reduce((a, b) => a + b, 0);
const sumStr = ds.length ? ds.join(' + ') : '0';
if(sum === n) setStatus(fmt('%n% = %sumStr% = %sum% — <b>perfect!</b>', { n: n, sumStr: sumStr, sum: sum }), 'ok');
else if(sum < n) setStatus(fmt('%n% = %sumStr% = %sum% < %n% — deficient.', { n: n, sumStr: sumStr, sum: sum }), 'def');
else setStatus(fmt('%n% = %sumStr% = %sum% > %n% — abundant.', { n: n, sumStr: sumStr, sum: sum }), 'ab');
console.log(fmt('n=%n%', { n: n }), fmt('divisorSum=%sum%', { sum: sum }));
}
function make(){
const p = Number(document.getElementById('p').value);
const mersenne = Math.pow(2, p) - 1; // 2^p - 1
const s2 = document.getElementById('status2');
if(!isPrime(mersenne)){
s2.className = 'status2 ab';
s2.innerHTML = fmt('2<sup>%p%</sup>−1 = %mersenne% is <b>not prime</b>, so no perfect number here.', { p: p, mersenne: mersenne });
return;
}
const perfect = Math.pow(2, p - 1) * mersenne;
s2.className = 'status2 ok';
s2.innerHTML = fmt('2<sup>%p%</sup>−1 = %mersenne% is a Mersenne prime → 2<sup>%v%</sup>×%mersenne% = <code>%perfect%</code>, an even perfect number.', { p: p, mersenne: mersenne, v: p - 1, perfect: perfect });
document.getElementById('num').value = perfect;
console.log(fmt('p=%p%', { p: p }), fmt('mersenne=%mersenne%', { mersenne: mersenne }), fmt('perfect=%perfect%', { perfect: perfect }));
}
document.getElementById('test').addEventListener('click', test);
document.getElementById('make').addEventListener('click', make);
document.getElementById('num').addEventListener('keydown', function(e){ if(e.key === 'Enter') test(); });
test();
<p class="hint">A <b>perfect</b> number equals the sum of its proper divisors (every divisor except itself). Type a number to test it, or generate an even perfect number from a Mersenne prime exponent.</p>
<div class="row">
<input id="num" type="number" min="1" value="28" />
<button id="test" type="button">Sum the divisors</button>
</div>
<div class="status" id="status">28 = 1 + 2 + 4 + 7 + 14 = 28 — perfect!</div>
<div class="gen">
<label for="p">Mersenne exponent p:</label>
<select id="p">
<option value="2">2</option>
<option value="3" selected>3</option>
<option value="5">5</option>
<option value="7">7</option>
<option value="11">11</option>
<option value="13">13</option>
</select>
<button id="make" type="button" class="ghost">Build 2ᵖ⁻¹(2ᵖ−1)</button>
</div>
<div class="status2" id="status2"></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 .8rem; line-height: 1.45; }
.row, .gen { display: flex; gap: .5rem; align-items: center; flex-wrap: wrap; margin: .5rem 0; }
.gen label { font-size: .9rem; color: #1d3557; font-weight: 600; }
input, select { font: 600 15px system-ui, sans-serif; padding: .4rem .6rem; border: 1px solid #adb1b8;
border-radius: 8px; }
input { width: 130px; }
.status, .status2 { font-size: 1rem; font-weight: 600; margin: .5rem 0; min-height: 1.4em; line-height: 1.4; }
.status.ok, .status2.ok { color: #0a7d33; }
.status.def { color: #1d6fb8; }
.status.ab { color: #c97a16; }
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; }
code { background: #eef2f6; padding: .1rem .35rem; border-radius: 5px; font-size: .92em; }
const fmt = (s, v) => s.replace(/%(\w+)%/g, (_, k) => String(v[k] ?? ''));
// A perfect number equals the sum of its proper divisors: 6 = 1+2+3, 28 = 1+2+4+7+14.
// Less than the number => deficient; more => abundant; exactly equal => perfect.
// Even perfect numbers are EXACTLY 2^(p-1)*(2^p - 1) where 2^p - 1 is a Mersenne prime
// (Euclid-Euler theorem). Whether any ODD perfect number exists is still OPEN.
function properDivisors(n){
const ds = [];
for(let d = 1; d <= n / 2; d++){ if(n % d === 0) ds.push(d); }
return ds;
}
function isPrime(n){
if(n < 2) return false;
for(let d = 2; d * d <= n; d++){ if(n % d === 0) return false; }
return true;
}
function setStatus(t, cls){ const s = document.getElementById('status'); s.innerHTML = t; s.className = 'status ' + cls; }
function test(){
const n = Math.floor(Number(document.getElementById('num').value));
if(!Number.isFinite(n) || n < 1){ setStatus('Enter a whole number ≥ 1.', ''); return; }
const ds = properDivisors(n);
const sum = ds.reduce((a, b) => a + b, 0);
const sumStr = ds.length ? ds.join(' + ') : '0';
if(sum === n) setStatus(fmt('%n% = %sumStr% = %sum% — <b>perfect!</b>', { n: n, sumStr: sumStr, sum: sum }), 'ok');
else if(sum < n) setStatus(fmt('%n% = %sumStr% = %sum% < %n% — deficient.', { n: n, sumStr: sumStr, sum: sum }), 'def');
else setStatus(fmt('%n% = %sumStr% = %sum% > %n% — abundant.', { n: n, sumStr: sumStr, sum: sum }), 'ab');
console.log(fmt('n=%n%', { n: n }), fmt('divisorSum=%sum%', { sum: sum }));
}
function make(){
const p = Number(document.getElementById('p').value);
const mersenne = Math.pow(2, p) - 1; // 2^p - 1
const s2 = document.getElementById('status2');
if(!isPrime(mersenne)){
s2.className = 'status2 ab';
s2.innerHTML = fmt('2<sup>%p%</sup>−1 = %mersenne% is <b>not prime</b>, so no perfect number here.', { p: p, mersenne: mersenne });
return;
}
const perfect = Math.pow(2, p - 1) * mersenne;
s2.className = 'status2 ok';
s2.innerHTML = fmt('2<sup>%p%</sup>−1 = %mersenne% is a Mersenne prime → 2<sup>%v%</sup>×%mersenne% = <code>%perfect%</code>, an even perfect number.', { p: p, mersenne: mersenne, v: p - 1, perfect: perfect });
document.getElementById('num').value = perfect;
console.log(fmt('p=%p%', { p: p }), fmt('mersenne=%mersenne%', { mersenne: mersenne }), fmt('perfect=%perfect%', { perfect: perfect }));
}
document.getElementById('test').addEventListener('click', test);
document.getElementById('make').addEventListener('click', make);
document.getElementById('num').addEventListener('keydown', function(e){ if(e.key === 'Enter') test(); });
test();
Then try the second button. Every even perfect number is built from a Mersenne prime — a prime of the form 2ᵖ − 1 — by the formula 2ᵖ⁻¹ × (2ᵖ − 1). This is the Euclid–Euler theorem: Euclid proved this recipe always yields a perfect number, and Euler (≈1750) proved every even perfect number must look exactly this way. Watch how a tiny prime explodes into a perfect number, and notice that no odd one ever appears.
Comments
Loading comments...