venerdì 10 giugno 2011

Programmazione..quale incubo! Generiamo i numeri primi con i vettori.

Eccoci di nuovo qui.
Perdonate la lunga assenza. Ci siamo lasciati l'ultima volta con un programma per la generazione dei numeri primi.
In questo programma vi sarete resi conti che non abbiamo utilizzato i vettori.
Bene, è ora di introdurli perché senza vettori la programmazione, ad un livello alto, è quasi impossibile.
Quindi, ci poniamo di fronte allo stesso problema, la generazione dei numeri primi ma stavolta utilizzaremo il "crivello di Eratostene": si scrivono N (a scelta) numeri naturali e si iniziano a togliere prima i multipli d 2, poi tutti i multipli di 3..ecc ecc . Partiamo da 2 perché naturalmente tutti i numeri sono multipli di 1 e chiuderemmo i giochi.
Iniziamo.
Scriviamo subito le righe fondamentali del nostro programma:


program primi
implicit none

end program

Benissimo. A questo punto dobbiamo generare il nostro vettore di N numeri naturali; per farlo utilizziamo un ciclo "do" per i che va da 1 ad N a passi di 1.

do i=1,N,1
v(i)=i
end do

L'espressione "v(i)=i" cosa significa? Significa che per i=1, la componente 1 di v sarà =1, per i=2 la componente 2 di v sarà uguale a 2 e così via, che è esattamente ciò che vogliamo giusto?
Che dobbiamo fare di importante ora? Dichiarare il nostro vettore e la variabile i:

integer::i
integer,dimension(50):: v

Quindi, con "integer" stiamo dicendo che il nostro vettore è costituito da interi, "dimension(50)" dice che il vettore v ha 50 componenti.
Ok.
Se però volessimo scegliere noi ogni volta quanti numeri analizzare?
In fortran esiste un modo per attribuire la dimensione ai vettori dopo la dichiarazione:

integer,dimension(:),allocatable::v

Così stiamo dicendo al programma che "allocheremo" dopo la memoria del vettore.
A questo punto diamo in input al programma il numero di numeri da analizzare

write(*,*), "inserisci il limite massimo"
read(*,*), N

Fatto ciò, aggiungiamo la riga in cui diciamo al programma che v avrà N componenti

write(*,*), "inserisci il limite massimo"
read(*,*), N
allocate (v(N))

Ricapitoliamo fin qui.

program primi

implicit none
integer::i
integer,dimension(:),allocatable::v

write(*,*), "inserisci il limite massimo"
read(*,*), N
allocate (v(N))

do i=1,N,1

v(i)=i
end do

end program


Benissimo. A questo punto dobbiamo applicare il crivello. Per farlo ci serviranno due "cicli do" e delle condizioni "if".
Scriviamo i 2 cicli:

do k=2,N,1
do j=2,N,1
np=v(k)*j
end do
end do

Cosa abbiamo fatto? Per ogni numero k, generiamo N numeri j e facciamo il prodotto tra la componente k del vettore v che sarà k stesso (sono tutti numeri naturali in ordine) e tutte le j da 2 a N. Esempio:

k=2
j=2
np=4
j=3
np=6
(fino a j=N)
k=3
j=2
np=6
e così via

In pratica "np" sono proprio i vari multipli. Dato che noi stiamo cercando i numeri primi (che non sono multipli di nessun numero), capite che vogliamo eliminare tutti gli np dal nostro vettore.
Per farlo, abbiamo necessità di un vettore di appoggio: non possiamo infatti modificare il vettore v mentre ci lavoriamo sopra. Dichiaramo un altro vettore "va" identico a v.

integer,dimension(:),allocatable::va

e lo "allochiamo" esattamente come abbiamo fattore per v, nello stesso punto.

allocate (va(N))

A questo punto
, aggiungiamo una semplice riga con la quale mettiamo =0 i numeri corrispondenti ai multipli "np" nel vettore "va":

do k=2,N,1
do j=2,N,1
np=v(k)*j
va(np)=0
end do
end do

Bene, abbiamo posto tutti i multipli =0.
Capite però che, poiché abbiamo N numeri e non infiniti, a volte la moltiplicazione potrebbe darci numeri più grandi di N. Allora mettiamo una condizione che ponga questi numeri =1:

if (np>N) then
np=1
end if

Ricapitoliamo fin qui, dichiarando anche tutte le variabili che abbiamo aggiunto

program primi
implicit none
integer::i,k,j,np
integer,dimension(:),allocatable::v
integer,dimension(:),allocatable::va

write(*,*), "inserisci il limite massimo"
read(*,*), N
allocate (v(N))
allocate (va(N))

do i=1,N,1

v(i)=i
end do

do k=2,N,1
do j=2,N,1
np=v(k)*j
if (np>N) then
np=1
end if
va(np)=0
end do
end do

end program


Cosa manca? La stampa dei numeri non multipli, cioé dei nostri numeri primi.
Allora, iniziamo un nuovo ciclo "do", stavolta da 1 a N e diciamo al programma di stamparci i numeri che non abbiamo posto =0 nel vettore va.

do y=1,N,1
if (va(y)/=0) then !se la componente y di va è diversa da 0 allora
write(*,*), va(y) !stampala
end if
end do

Mettiamo tutto insieme.


program primi
implicit none
integer::i,k,j,np
integer,dimension(:),allocatable::v
integer,dimension(:),allocatable::va

write(*,*), "inserisci il limite massimo"
read(*,*), N
allocate (v(N))
allocate (va(N))

do i=1,N,1

v(i)=i
end do

do k=2,N,1
do j=2,N,1
np=v(k)*j
if (np>N) then
np=1
end if
va(np)=0
end do
end do


do y=1,N,1
if (va(y)/=0) then !se la componente y di va è diversa da 0 allora
write(*,*), va(y) !stampala
end if
end do

end program

Ecco i vostri numeri primi.

Nessun commento:

Posta un commento