Un numero si dice perfetto se è uguale alla somma dei suoi divisori, escluso se stesso. I primi quattro numeri perfetti (6, 28, 496, 8128) erano già noti ai greci. Il quinto (33.550.336) si trova in un manoscritto medioevale anonimo. I due successivi (8.589.869.056 e 137.438.691.328) furono scoperti dal matematico Bolognese Pietro Antonio Cataldi, nel 1588.
Ci sono molte cose interessanti relativamente ai numeri
perfetti, tra cui per esempio il fatto che non è stato
ancora scoperto alcun perfetto dispari, anche se, per ora, non
si può escludere che ce ne siano. Gli interessati possono
effettuare anche una ricerca sulla rete dove si trova una
quantità impressionante di materiale su questo argomento.
Qui ci preme segnalare un fatto interessante dal punto di vista
informatico: l'algoritmo elementare per la ricerca dei
numeri perfetti non è in grado di scoprire, in tempi
ragionevoli, alcunché di nuovo rispetto alle conoscenze
dei greci. Se, per esempio, si volesse provare ad usare questo
programma per cercare il quinto numero perfetto, bisognerebbe
impostare un intervallo di ricerca almeno tra 8129 e
100.000.000: non abbiamo fatto il tentativo, ma probabilmente 24
ore di calcolo non sarebbero sufficienti!! Esiste anche una
"scorciatoia", almeno per i perfetti pari: si tratta
di un teorema la cui idea di base è dovuta ad Euclide e
che fu poi dimostrato completamente da Eulero (ogni numero
perfetto pari è della forma , ove
il numero tra parentesi è un numero, detto di Mersenne,
primo).
Tutto il lavoro in javascript è fatto dalla funzione qui
sotto, dove abbiamo messo in grassetto la parte importante del
codice; il resto è controllo dell'input
(all'inizio) e ordinamento dei divisori per la stampa (nella
seconda metà). Per velocizzare un po' il calcolo
abbiamo fatto la seguente osservazione: se d è
un divisore di un numero n, più grande della
radice quadrata di n, allora ,
cioè n/d è un divisore minore della
radice di n. Allora se troviamo un divisore
d1 minore della radice di n,
basterà aggiungere all'elenco dei divisori anche
n/d1. L'elenco dei divisori non
risulterà più ordinato, ma, se non abbiamo
esigenze di stamparli in ordine, questo non crea problemi. Nel
programma proposto abbiamo introdotto un ordinamento, appunto
per comodità di stampa.
function calcola()
{
document.getElementById('risultato').value="";
var
min=parseInt(document.getElementById('minimo').value);
var
max=parseInt(document.getElementById('massimo').value);
if (isNaN(min) || isNaN(max)|| min<0 || max<0)
//controllo dell'input
{
window.alert("Dati in ingresso non
validi.\nInserisci interi maggiori o uguali a 0.");
return; //L'istruzione causa l'interruzione
della funzione, perché essa non è
calcolabile
}
if ((min>10000 || max>10000) &&
(Math.abs(min-max)>100))
{
if (!window.confirm("Con i dati che hai introdotto
potrei averne per ore!!\nIn ogni caso se proprio vuoi rischiare
premi OK."))
{
return;
}
}
if (max<min) //scambio in modo da avere max sempre
più grande di min
{
var temp;
temp=min;
min=max;
max=temp;
}
if (min==1) min=2;
if (max==1) max=2;
var divisori=new Array(); //array dove piazziamo i divisori
propri del numero in esame
divisori[0]=0;
var perfetti=0; //variabile dove piazziamo quanti perfetti
abbiamo trovato
for (var k=min;k<=max;k++) //ciclo for per scandire
i numeri dell'intervallo proposto dall'utente
{
var j=0; //variabile per indicizzare i divisori
trovati
for (var i=2;i<Math.sqrt(k);i++)
{
if (k%i == 0)
{
j++;
divisori[j]=i; //aggiungo il divisore trovato
j++;
divisori[j]=Math.floor(k/i); //aggiungo anche il divisore
complementare
} //end of if
} //end of for(var i...)
if (k%Math.sqrt(k)==0) //se del caso si aggiunge anche
la radice quadrata del numero
{
j++;
divisori[j]=Math.sqrt(k);
}
var somma=1; //Il divisore 1 non esce dal calcolo
precedente
for (var p=1;p<=j;p++)
{
somma=somma+divisori[p];
} //end of for (var p...)
if (k==somma)
{
perfetti++;
document.getElementById('risultato').value=document.getElementById('risultato').value+"**Il
numero "+k+" è
perfetto.**\n";
var divisori1 = new Array(); /*uso questo
array per piazzare solo i divisori del numero in esame,
in modo da poterlo ordinare senza problemi con residui dei
divisori
di altri numeri già esaminati*/
divisori1[0]=1;
for (var p=1;p<=j;p++)
{
divisori1[p]=divisori[p];
}
divisori1.sort(function(a,b) {return a-b;});
//ordinamento numerico crescente
var output="1 "; //in questa
stringa metterò i divisori, appena ordinati, separati da
uno spazio
for (var p=1;p<=j;p++)
{
output=output+divisori1[p]+" ";
}
document.getElementById('risultato').value=document.getElementById('risultato').value+"I
suoi divisori sono: "+output+"\n";
} //end of if k==somma
} //end of for(var k...)
if (perfetti==0)
{
document.getElementById('risultato').value=ingresso.risultato.value+"\n
Non esistono numeri perfetti nell'intervallo
richiesto.";
}
} //end of calcola()