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()