Delucidazione programma
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..
Mi sapete dare una mano??
Grazie mille..
Risposte
Ciao...premetto che prima di scriverti sono andato in wikipedia a vedere cos'è un numero perfetto
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
Spero di non aver sbaglito nulla perchè faccio ing. meccanica e quindi non è il mo campo...però spero di esserti stato utile.
Ciao ciao

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

Spero di non aver sbaglito nulla perchè faccio ing. meccanica e quindi non è il mo campo...però spero di esserti stato utile.
Ciao ciao
MMM.. Grazie per l'aiuto tantissimo; Ma non esiste un modo "leggermente" più breve e semplice??
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
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
).
Per qualunque cosa hai bisogno, se posso ti aiuterò...
Ciau!!
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


Per qualunque cosa hai bisogno, se posso ti aiuterò...
Ciau!!
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
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
"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.
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...
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...

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!!
Ancora grazie a tutti!!
