Delucidazione programma

stellacometa
Ragazzi non riesco a creare un programma in Pascal che stampi la lista dei numeri perfetti da uno a n, n lo immetterà l'utente...

Mi sapete dare una mano??

Grazie mille..

Risposte
*pizzaf40
Ciao...premetto che prima di scriverti sono andato in wikipedia a vedere cos'è un numero perfetto :-D

Cmq questo l'ho trovato interessante perchè ti da anche i primi 10 numeri perfetti...http://it.wikipedia.org/wiki/Numero_perfetto

Non sono un esperto del campo, ma un anno fa ho fatto un programma sugli elementi finiti in Fortran (che è simile al Pascal).
Apparte il dubbio che mi è venuto sul fatto che, essendo molto grandi e dovendo essere precisi e interi, non son se si riesce a trovarli tutti dieci...non puoi usare la variabile con rappresentazione esponenziale, perchè l'arrotondamento numerico porterebbe ad errori inaccettabili essendo numeri interi...quindi dovrai usare un sacco di bit per ogni numero...anche se i primi sono piccoli.

Cmq il numero perfetto è pari...quindi salti tutti i dispari con un ciclo while $i=1->n$ e prendendo il numero $x=2n$. Quindi se l'utente del programma vuole trovare i numeri perfetti minori di $z$, dovrai porre $n=z/2$.
Poi, non avendo molta esperienza, l'unico modo che mi è venuto in mente consiste nel fare tre azioni:

1) prendi $x/2$ che, essendo $x$ un numero pari, dovrà essere per forza un suo divisore...poi poni $s=x/2$;

2) prendi $x/3$, ne prendi la parte intera $I$ (non ricordo il comando ma so che c'è), fai $x/3-I$ e fai il controllo che sia uguale a 0 (per vedere se $x/3$ è intero)...se lo è anche $x/3$ è un divisore, sennò no...se è un divisore poni $s=s+x/3$, cioè lo sommi all'$x/2$ di prima;

3) parti con un ciclo da con $i=4->x/3-1$ e fai lo stesso lavoro, cioè $x/i$, prendi $I$, poi $x/i-I$ per controllare se $x/i$ è intero. Se non lo è, passi ad $i+1$, ma se lo è fai $s=s+x/i$ e poi passi al successivo. Quando arrivi a fine ciclo ($i=x/3$), confronti $x$ ed $s$...se sono uguali, il loro valore è un numero perfetto!!!

L'ho voluto dividere in pezzi, perchè se $x$ è molto grande e tu facessi solo il terzo passo per $i=2->x/2-1$ (quindi più automatizzato), significherebbe che devi controllare un sacco di numeri tra $x/2$ e $x/3$ che sicuramente non saranno divisori di $x$!! Quindi come ho fatto risparmi un bel po' di calcoli e "if" al cpu. Inoltre, ogni passo aggiuntivo che metti, potrai fare l'ultimo passo con $i=5->x/4-1$ (con un passo in più del mio), con $i=6->x/4-1$ (con 2 passi in più), ecc...capirai che se hai $x$ di 50 cifre, ogni passo aggiunto è un po' più di lavoro per te ma un sacco di lavoro in meno ogni volta per il cpu (che si tramuta quindi in velocità). Ma all'abbassarsi di $x$ il vantaggio va diminuendo...quindi la scelta di quanti passi fare dipende dall'utlizzo che devi fare del programma e dai valori di $x$ che immetterai (o di $z$ tornando alle lettere dell'inizio). Probabilmaente ci sarebbe anche un modo di automatizzare la scelta dei passi in base a un criterio di confronto dipendente da $x$ (e non da $z$, cioè ottimizzare ogni singola ricerca dei divisori per tutti i numeri che il cpu controlla) ma pensare a questo mi richiederebbe tempo che non ho...ho un esame domani mattina :-D

Spero di non aver sbaglito nulla perchè faccio ing. meccanica e quindi non è il mo campo...però spero di esserti stato utile.

Ciao ciao

stellacometa
MMM.. Grazie per l'aiuto tantissimo; Ma non esiste un modo "leggermente" più breve e semplice??

*pizzaf40
Eh, ho paura di no...potresti mandare a quel paese rendimento e velocità del programma e fare solo il terzo passaggio per $i=2->x/2-1$ (visto che la divisibilita per 1 è ovvia) dando come valore della somma iniziale $s=1$...o anche per $i=3->x/3-1$ dando come valore di partenza della somma $s=1+2$ (questo prevede anche che tu faccia il passaggio 1).

Scusa, ma in realtà ho anche fatto un errore che ora ho notato...parti sempre con $s=1$...poi:

-nel passagio 1) in realtà è $s=s+2(=1+2)$ (e non $s=s+x/2$);
-alla stessa maniera, nel passagio 2) in realtà è $s=s+3(=1+2+3)$;
-ugualmente per il ciclo generale, nel passagio 3) in realtà è $s=s+i(=1+2+3+....+i)$;

Così è il modo più semplice che mi è venuto...leggendo la tua domanda in maniera lata, il modo più semplice è senza dubbio quello di andare il wikipedia, copiare i primi 10 valori di numeri perfetti, copiarli in un programmino che (all'immissione di $n$) restituisce i valori $n_p:-D ma questa è proprio una furbata...se ti controllano il testo sei cagata (o ricevi i complimenti per la furbizia, se disponi di un fondoschiena ragguardevole :D ).

Per qualunque cosa hai bisogno, se posso ti aiuterò...

Ciau!!

codino75
se non erro pizza ti ha suggerito di andare a vedere se un dato numero e' perfetto.
prova anche a considerare invece di 'generare' i numeri perfetti a aprtire dalla definizione.
non so se e' fattibile, ma vale la pena di provare.
alex

TomSawyer1
"pizzaf40":
Cmq il numero perfetto è pari...

Bisogna ancora dimostrarlo, quindi bisogna capire megli che tipo di programma devi scrivere. Se il tuo professore chiede solo una cosa pratica, allora puoi considerare solo i pari (dato che non ne esistono di dispari minori di $10^{300}$). Quindi potresti addirittura trasformare il programma nella sola ricerca di primi di Mersenne, dato che un numero perfetto pari e' $2^{p-1}(2^p-1)$, con $2^p$ primo di Mersenne.

E' richiesta qualche complessita' computazionale, inoltre?

EDIT: Sergio, non e' detto che non esistano i nnumeri perfetti dispari. Quindi bisogna capire se il programma richiesto deve essere formale o pratico.

*pizzaf40
Sì, è vero che non è dimostrato che è pari, ma è appunto verificato che tutti i numeri perfetti rappresentabili in Pascal sono pari...il ciclo di scelta dei numeri da sottoporre a verifica che avevo proposto, infatti considerava solo i pari per quel motivo.

In effetti ricorrere a $2^n(2^(n+1)-1)$ se $(2^(n+1)-1)$ è primo è una ottima soluzione (nel momento in cui è verificato che si ottengono tutti i numeri perfetti rappresentabili in pascal, come ha fatto Sergio!)...questo infatti permetterebbe di dover verificare molti meno numeri..cioè se è primo $(2^(n+1)-1)$, e in caso positivo calcolarsi $2^n(2^(n+1)-1)$. I primi 7 num. perfetti si otterrebbero con la verifica di solo 18 numeri!!
Ma mettere i valori utili degli $n$ verificati in un array, sarebbe allo stesso livello di copiare i numeri primi già ottenuti, dicendo al programma di scegliere quelli inferiori al valore richiesto dall'utente...per un programma che si ricavi effettivamente il valore partendo da questa definizione ($2^n(2^(n+1)-1)$ se $(2^(n+1)-1)$ è primo) bisogna fargli verificare che $(2^(n+1)-1)$ è primo in maniera concettualmente simile a quanto ho proposto sopra...

Ovviamente l'approccio proposto da sergio ha il grosso vantaggio di far lavorare un sacco meno il cpu perchè richiede molti meno confronti e calcoli, quindi rende il programma moooooolto più veloce... :-D

stellacometa
Grazie tantissimo per l'aiuto...erano proprio le informazioni che mi servivano...se trovo dei "bug" appena compilo il programma lo posto e vediamo il da farsi, ma spero e credo di non avere problemi...

Ancora grazie a tutti!! :wink:

Rispondi
Per rispondere a questa discussione devi prima effettuare il login.