Visualizzazione post con etichetta programmazione..quale incubo. Mostra tutti i post
Visualizzazione post con etichetta programmazione..quale incubo. Mostra tutti i post

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.

martedì 8 febbraio 2011

Programmazione..quale incubo! (due postulati)

1.Tra tutti gli errori che vi tira fuori il programma, solo uno è reale...dopo aver provato a correggere gli pseudo-errori, comunque non lo troverete.
2. Inizierete a parlare col programma...gli chiederete il perché vi dice "segmentetion fault"...E' inutile, non vi risponderà.

martedì 1 febbraio 2011

Programmazione..quale incubo! Generiamo i numeri primi.

Eccoci di nuovo qui.
Nella nostra ultima lezione abbiamo generato i numeri della serie di Fibonacci. Ora vediamo come fare a generare i primi N numeri primi.
Ormai avete imparato quali sono le righe fondamentali da scrivere immediatamente:

program primi
implicit none

end program

Perfetto. Prima di tutto pensiamo a quale può essere un modo intuitivo per individuare i numeri primi, ricordandoci che tutti i numeri sono divisibili per 1 e per loro stessi. Allora, partiamo da 3 e vediamo se è divisibile per i numeri che lo precedono, cioè 2. Non lo è, quindi è primo. Andiamo con 4: 4 non è divisibile per 3 ma lo è per 2 e quindi lo togliamo. Vediamo 5: non è divisibile per 4, nè per 3, nè per 2 quindi è primo.
Ci siete?
Ora dobbiamo tradurre questo ragionamento in linguaggio fortran.
Sicuramente avremo bisogno di fare una divisione tra coppie di numeri per verificare se siano multipli o no giusto?
In fortran esiste una funzione che ci da il resto di una divisione tra 2 numeri:

mod(a,b)

Se questa funzione è diversa da 0, significa che a e b non sono multipli tra loro, altrimenti sì. Ricordiamoci che ad ogni funzione va associata una variabile, cioè

r=mod(a,b)

Ottimo. Naturalmente a e b varieranno perché dobbiamo controllare tutti i numeri fino ad un numero N che decidiamo noi: questo significa che dovrà esserci un ciclo, forse due.
Iniziamo: prima di tutto diciamo al programma quanti numeri primi vogliamo generare. Ricordiamoci che ogni variabile che inseriamo deve essere dichiarata.

program primi
implicit none
integer:: N
write(*,*) "Quanti numeri primi vuoi generare?"
read(*,*) N
end program

(Se non ricordate alcuni comandi, andate nei post precedenti).
Ho accennato al fatto che avremo due cicli: perché? Perché dobbiamo fare un confronto tra due numeri variabili. Per farlo dobbiamo prendere ogni numero a partire da 3 (1 e 2 sono i primi due numeri e sono primi "per definizione")

do i=3,N

e poi confrontarlo con tutti i numeri che lo precedono, a partire da 2 fino al numero subito prima che sarà (i-1)

do j=2,i-1

Quindi il secondo "do" sarà dentro al primo: così per i=3, confrontiamo 3 con j da 2 a (3-1) cioè solo con 2 in questo caso. Poi passiamo a i=4 e lo confrontiamo con j da 2 a (4-1)=3 ecc ecc.
Ricordiamoci che gli indici di un ciclo devono essere interi:

program primi
implicit none
integer:: N,i,j
write(*,*) "Quanti numeri primi vuoi generare?"
read(*,*) N
do i=3,N
do j=2,i-1
end do
end do
end program


Ok. E' il momento di inserire la funzione mod(a,b). Dove? Dentro al secondo "do" perché dobbiamo calcolarla per ogni coppia, giusto? Ricordiamoci di dichiarare sia la funzione che la variabile associata.

program primi
implicit none
integer:: N,i,j,mod,r
write(*,*) "Quanti numeri primi vuoi generare?"
read(*,*) N
do i=3,N
do j=2,i-1
r=mod(i,j)
end do
end do
end program


A questo punto dobbiamo controllare se il resto r è o no =0 e dirgli che se lo trova =0 deve uscire dal ciclo "j" e passare al numero "i" successivo; cioè, i=6 darà resto zero con j=3. A quel punto lui passerà ad analizzare i=7 perché 6 non è primo. Ci siamo?
Come facciamo a dire questo? In fortran c'è un comando con il quale diciamo: "se incontri questa condizione fai questa cosa".

if (condizione) then
istruzione
end if

Nel nostro caso sarà:

if (r==0) then
exit
end if

Gli abbiamo detto: se il resto è identico (per questo ci va il == e non solo =) a zero, esci dal ciclo.
Dove lo mettiamo? Dopo aver calcolato la funzione mod.


program primi
implicit none
integer:: N,i,j,mod,r
write(*,*) "Quanti numeri primi vuoi generare?"
read(*,*) N
do i=3,N
do j=2,i-1
r=mod(i,j)
if (r==0) then
exit
end if
end do
end do
end program


Bene. Però così non facciamo altro che uscire dal ciclo ogni volta che c'è un numero non primo. Noi vogliamo farci scrivere i numeri primi quando li trova. Allora dobbiamo mettergli un'altra condizione, cioè utilizzare un altro "if". Qual è questa condizione? Sicuramente che r sia diverso da zero ma capiamo che il controllo deve andare avanti fino ad un numero abbastanza vicino ad "i".
Mi spiego meglio: un numero dispari sicuramente non è divisibile per 2 ma noi non vogliamo che il programma si blocchi perché quel numero potrebbe essere divisibile per un numero successivo a 2. Allora dobbiamo dirgli:

if ((r/=0) .AND. (trigger=i-3)) then
write(*,*)'Ho trovato',i
end if

Cioè, se trovi che la funzione "mod" è diversa da zero (r/=0) e contemporaneamente (.AND. logico) siamo ad un numero "j" che equivale a i-3 (trigger=i-3), allora sta sicuro che quello è primo e scrivilo sul monitor.
Dato che questo "if" si aggiunge all' "if" precedente, il primo "if" non va chiuso e al posto del secondo "if" dovremo mettere "else if" (altrimenti se) e poi chiudere:

if (r==0) then
exit
else if ((r/=0) .AND. (trigger=i-3)) then
write(*,*)'Ho trovato',i
end if

La variabile "trigger" ci serve per contare il numero di cicli "j". All'inizio sarà =0 e poi aumenterà di uno ad ogni ciclo j:

trigger= trigger+1

Mettiamo questi concetti insieme:

program primi
implicit none
integer:: N,i,j,mod,r,trigger
write(*,*) "Quanti numeri primi vuoi generare?"
read(*,*) N
trigger=0
do i=3,N
do j=2,i-1
r=mod(i,j)
if (r==0) then
exit
else if ((r/=0) .AND. (trigger=i-3)) then
write(*,*)'Ho trovato',i
end if
trigger=trigger+1
end do
end do
end program


Avete creato un algoritmo che vi genere N numeri primi! Complimenti!

lunedì 31 gennaio 2011

Programmazione..quale incubo! Generiamo i numeri primi.

Eccoci di nuovo qui.
Nella nostra ultima lezione abbiamo generato i numeri della serie di Fibonacci. Ora vediamo come fare a generare i primi N numeri primi.
Ormai avete imparato quali sono le righe fondamentali da scrivere immediatamente:

program primi
implicit none

end program

Perfetto. Prima di tutto pensiamo a quale può essere un modo intuitivo per individuare i numeri primi, ricordandoci che tutti i numeri sono divisibili per 1 e per loro stessi. Allora, partiamo da 3 e vediamo se è divisibile per i numeri che lo precedono, cioè 2. Non lo è, quindi è primo. Andiamo con 4: 4 non è divisibile per 3 ma lo è per 2 e quindi lo togliamo. Vediamo 5: non è divisibile per 4, nè per 3, nè per 2 quindi è primo.
Ci siete?
Ora dobbiamo tradurre questo ragionamento in linguaggio fortran.
Sicuramente avremo bisogno di fare una divisione tra coppie di numeri per verificare se siano multipli o no giusto?
In fortran esiste una funzione che ci da il resto di una divisione tra 2 numeri:

mod(a,b)

Se questa funzione è diversa da 0, significa che a e b non sono multipli tra loro, altrimenti sì. Ricordiamoci che ad ogni funzione va associata una variabile, cioè

r=mod(a,b)

Ottimo. Naturalmente a e b varieranno perché dobbiamo controllare tutti i numeri fino ad un numero N che decidiamo noi: questo significa che dovrà esserci un ciclo, forse due.
Iniziamo: prima di tutto diciamo al programma quanti numeri primi vogliamo generare. Ricordiamoci che ogni variabile che inseriamo deve essere dichiarata.

program primi
implicit none
integer:: N
write(*,*) "Quanti numeri primi vuoi generare?"
read(*,*) N
end program

(Se non ricordate alcuni comandi, andate nei post precedenti).
Ho accennato al fatto che avremo due cicli: perché? Perché dobbiamo fare un confronto tra due numeri variabili. Per farlo dobbiamo prendere ogni numero a partire da 3 (1 e 2 sono i primi due numeri e sono primi "per definizione")

do i=3,N

e poi confrontarlo con tutti i numeri che lo precedono, a partire da 2 fino al numero subito prima che sarà (i-1)

do j=2,i-1

Quindi il secondo "do" sarà dentro al primo: così per i=3, confrontiamo 3 con j da 2 a (3-1) cioè solo con 2 in questo caso. Poi passiamo a i=4 e lo confrontiamo con j da 2 a (4-1)=3 ecc ecc.
Ricordiamoci che gli indici di un ciclo devono essere interi:

program primi
implicit none
integer:: N,i,j
write(*,*) "Quanti numeri primi vuoi generare?"
read(*,*) N
do i=3,N
do j=2,i-1
end do
end do
end program


Ok. E' il momento di inserire la funzione mod(a,b). Dove? Dentro al secondo "do" perché dobbiamo calcolarla per ogni coppia, giusto? Ricordiamoci di dichiarare sia la funzione che la variabile associata.

program primi
implicit none
integer:: N,i,j,mod,r
write(*,*) "Quanti numeri primi vuoi generare?"
read(*,*) N
do i=3,N
do j=2,i-1
r=mod(i,j)
end do
end do
end program


A questo punto dobbiamo controllare se il resto r è o no =0 e dirgli che se lo trova =0 deve uscire dal ciclo "j" e passare al numero "i" successivo; cioè, i=6 darà resto zero con j=3. A quel punto lui passerà ad analizzare i=7 perché 6 non è primo. Ci siamo?
Come facciamo a dire questo? In fortran c'è un comando con il quale diciamo: "se incontri questa condizione fai questa cosa".

if (condizione) then
istruzione
end if

Nel nostro caso sarà:

if (r==0) then
exit
end if

Gli abbiamo detto: se il resto è identico (per questo ci va il == e non solo =) a zero, esci dal ciclo.
Dove lo mettiamo? Dopo aver calcolato la funzione mod.


program primi
implicit none
integer:: N,i,j,mod,r
write(*,*) "Quanti numeri primi vuoi generare?"
read(*,*) N
do i=3,N
do j=2,i-1
r=mod(i,j)
if (r==0) then
exit
end if
end do
end do
end program


Bene. Però così non facciamo altro che uscire dal ciclo ogni volta che c'è un numero non primo. Noi vogliamo farci scrivere i numeri primi quando li trova. Allora dobbiamo mettergli un'altra condizione, cioè utilizzare un altro "if". Qual è questa condizione? Sicuramente che r sia diverso da zero ma capiamo che il controllo deve andare avanti fino ad un numero abbastanza vicino ad "i".
Mi spiego meglio: un numero dispari sicuramente non è divisibile per 2 ma noi non vogliamo che il programma si blocchi perché quel numero potrebbe essere divisibile per un numero successivo a 2. Allora dobbiamo dirgli:

if ((r/=0) .AND. (trigger=i-3)) then
write(*,*)'Ho trovato',i
end if

Cioè, se trovi che la funzione "mod" è diversa da zero (r/=0) e contemporaneamente (.AND. logico) siamo ad un numero "j" che equivale a i-3 (trigger=i-3), allora sta sicuro che quello è primo e scrivilo sul monitor.
Dato che questo "if" si aggiunge all' "if" precedente, il primo "if" non va chiuso e al posto del secondo "if" dovremo mettere "else if" (altrimenti se) e poi chiudere:

if (r==0) then
exit
else if ((r/=0) .AND. (trigger=i-3)) then
write(*,*)'Ho trovato',i
end if

La variabile "trigger" ci serve per contare il numero di cicli "j". All'inizio sarà =0 e poi aumenterà di uno ad ogni ciclo j:

trigger= trigger+1

Mettiamo questi concetti insieme:

program primi
implicit none
integer:: N,i,j,mod,r,trigger
write(*,*) "Quanti numeri primi vuoi generare?"
read(*,*) N
trigger=0
do i=3,N
do j=2,i-1
r=mod(i,j)
if (r==0) then
exit
else if ((r/=0) .AND. (trigger=i-3)) then
write(*,*)'Ho trovato',i
end if
trigger=trigger+1
end do
end do
end program


Avete creato un algoritmo che vi genere N numeri primi! Complimenti!

lunedì 20 dicembre 2010

Programmazione..quale incubo! Serie di Fibonacci.

Eccoci di nuovo qui!
Come promesso, a questo punto possiamo affrontare un programma che ci calcoli la serie di Fibonacci:
0,1,1,2,3,5,8,13,21,34,55..

Primo passo: iniziate a ragionare con carta e penna alla mano.
Vogliamo generare dei numeri, a partire dallo zero, tali per cui ognuno sia la somma dei precedenti 2.
Perciò, se poniamo a=0 e b=1 avremo c=0+1=1. Ed ecco i primi 3 numeri.
Per passare ai successivi?
Porremo a=b=1 e b=c=1 e quindi la nuova c sarà 2. E così via.

Bene. Ora che abbiamo in mente la relazione fondamentale cominciamo a costruire il programma.
Un consiglio che posso darvi è quello di dichiarare le variabili mano mano che le aggiungete, nè prima (non saprete mai all'inizio del programma di quante e di che tipo avrete bisogno) né dopo (ve lo dimenticherete).
Il corpo del programma naturalmente sarà:

program fibonacci
implicit none

end progam

Perfetto! Aggiungiamoci la relazione che abbiamo scritto sul foglio, dichiarando le variabili: dato che stiamo parlando di interi saranno intere.

program fibonacci
implicit none
integer::a,b,c
a=0
b=1
c=a+b
a=b
b=c
end program


Ok. Cosa fa così il programma?Vediamo. Parte da a=0 e b=1, ne fa la somma una volta uguagliandola a c e poi pone a=b e b=c.
Corretto ma lo fa una volta soltanto. Noi vogliamo almeno 10 numeri della serie, cioè vogliamo fargli fare questa operazione 10 volte.
Come glielo diciamo? Con un ciclo:

do i=1,10,1
end do

Gli stiamo dicendo: fai l'operazione seguente da per 10 volte a partire da 1 e fallo a passi di 1 (l'ultimo numero). Quindi, ricordandoci di avere inserito la variabile i e quindi di dichiararla come un intero:

program fibonacci
implicit none
integer::a,b,c,i
a=0
b=1
do i=1,10,1
c=a+b
a=b
b=c
end do
end program


Perché lì? Perché se l'avessimo messo prima di a=0 e b=1, all'inizio di ogni ciclo avremmo avuto sempre a=0 e b=1 e perciò c sarebbe sempre stato 1.
In questo modo invece 0 e 1 sono i primi due numeri della serie, poi calcola i successivi.
Benissimo. Se volessimo decidere di volta in volta quanti numeri vogliamo calcolare?
Semplice. Gli diamo noi un numero 'n' all'inizio del programma. Come? Vi ricordate l'istruzione write/read?

program fibonacci
implicit none
integer::a,b,c,i
write(*,*) "quanti numeri vuoi calcolare?"
read(*,*), n
a=0
b=1
do i=1,10,1
c=a+b
a=b
b=c
end do
end program


Ora, al posto del 10 all'interno del ciclo ci andrà 'n' che andrà anche dichiarata.


program fibonacci
implicit none
integer::a,b,c,i,n
write(*,*) "quanti numeri vuoi calcolare?"
read(*,*), n
a=0
b=1
do i=1,n,1
c=a+b
a=b
b=c
end do
end program


Ultimo passaggio: volgio che il computer mi scriva i numeri.
Cosa uso? L'istruzione write.

program fibonacci
implicit none
integer::a,b,c,i,n
write(*,*) "quanti numeri vuoi calcolare?"
read(*,*), n
a=0
b=1
write(*,*),a
write(*,*),b
do i=1,n,1
c=a+b
a=b
b=c
write(*,*),c
end do
end program


I primi 2 write sono fuori dal ciclo perché voglio che mi stampi anche i primi due numeri che uso perché sono i primi due numeri della serie.
L'altro write è nel ciclo perché voglio che lui mi scriva tutti gli n numeri.

Ecco qui. Ce l'abbiamo fatta!

E la prossima volta, vedremo come generare n numeri primi, introducendo un'altra istruzione.

martedì 30 novembre 2010

Programmazione..quale incubo! (appendice)

Piccole (grandi) parentesi.

- In fortran maiuscole e minuscole sono indistinguibili, perciò se iniziate a mettere variabili 'm' ed 'M' lui impazzisce:

- Attenzione: in alcune versioni di fortran la lettera 'c', se nella prima colonna, la legge come commento:

- Il termine "far girare il programma" significa che, dopo averlo scritto il computer:
1. compilazione: il computer lo tradurrà da codice sorgente (linguaggio scritto da noi in fortran) a codice oggetto (il suo linguaggio macchina) e lo esaminerà punto per punto per vedere se gli sta bene quello che abbiamo scritto;
2. esecuzione: il computer renderà il programma eseguibile, dopo averlo unito alle cosiddette 'librerie' (archivi del computer o nostri) tramite un 'linker'.

- ATTENZIONE!!
Legge di Murphy: Il programma non funzionerà mai al primo colpo.
Cosa fare quando il computer inizia a farci un elenco infinito di errori?
1: distinguere tra WARNING (guarda sta cosa non è che mi piaccia tanto ma può anche andare) ed ERROR (cambia sta cosa e non provarci mai più!).
2: essere coscienti che se l'errore viene spiegato bene (tipo: 'variable x is not an implicit type') allora si corregge e via. Se invece risulta incomprensibile, potrebbe essere dovuto ad un altro errore precedente che fa impazzire il programma e che scompare quando eliminiamo il primo;
3: se continuano a sussistere errori, iniziare il "debugging".
Che vor dì?
Vuol dire che dobbiamo iniziare a leggerlo dalla prima riga, magari togliendo e poi rimettendo parti (evitando di eliminare 'end program' o 'program' iniziale). Mi spiego: dobbiamo iniziare ad eliminare le righe non necessarie (per esempio le operazioni nel programma che abbiamo scritto) , una, due, tre..finchè in un momento davvero di soddisfazione finalmente il programma va.
Allora sappiamo che l'ultima riga tolta era il problema e sappiamo dove andare a correggere!
4: ricordatevi che sbagliare una virgola o una parentesi può "uccidere" il programma, quindi non sottovalutatele!!
Cinque: attenzione ai numeri negativi, troppo grandi o troppo piccoli. I linguaggi di programmazione non li amano e spesso gli errori sono dovuti a questo.
Provate per esempio a farvi scivere 2**32: non gli piace, vi darà overflow.
Invece un bel 2**30 lo gradisce di più.

Detto ciò, non vi biasimo se continuate a pensare che non amerete mai l'informatica.

Programmazione..quale incubo! (fortran2)

Eccoci di nuovo qui.
Ci siamo lasciati nella soddisfazione di aver fatto fare un'operazione aritmetica al nostro computer.
A questo punto vogliamo spingerci oltre. Nel primo passo ci siamo lasciati chiedendoci: "
E se volessimo decidere di cambiare gli addendi di volta in volta?"
E' arrivato il momento di conoscere il potere che abbiamo di cambiare i numeri da utilizzare ogni volta che facciamo girare il programma.
Dunque,
il programma finale della prima 'lezione' era il seguente:


Program nome programma
implicit none
integer::x
x=7+5
write (*,*) 'il risultato della somma 7+5 è', x
End program

Come con il comando "write" diciamo al computer "scrivimi ciò che ti dico", intuitivamente col comando "read" gli possiamo dire "leggi ciò che scrivo". Dove? Sempre dopo la dichiarazione delle variabili:

Program nome programma
implicit none
integer::x
read (*,*), a,b
x=7+5
write (*,*) 'il risultato della somma 7+5 è', x
end program

Gli abbiamo detto leggi i numeri a e b che scriverò sul monitor (primo *) nel formato binario, cioè nel tuo formato standard (secondo *).
Guardando il programma però dovrebbe sorgervi un dubbio: dove li ho messi i numeri a e b che digito all'interno dell'operazione?
Da nessuna parte: in questo modo voi potete digitare quello che volete ma lui farà sempre 7+5.
Dove dobbiamo inserirli? Naturalmente al posto di 7+5.

Program nome programma
implicit none

integer::x
read (*,*), a,b
integer::x
x=a+b
write (*,*) 'il risultato della somma a+b è', x
end program


Ora sì.
Prima domanda: siete sicuri che quando farete partire il programma e vi apparira un trattino lampeggiante sul monitor voi vi ricorderete che dovrete digitare 2 numeri? Magari adesso sì ma vi assicuro che domani lo avete già dimenticato.
Allora chiedete al computer, anzi imponetegli di ricordarvelo, sempre tramite 'write'. Dove? Prima dell'istruzione che glieli fa leggere:

Program nome programma
implicit none

integer::x
write(*,*) 'inserisci due numeri a e b'
read (*,*), a,b
x=a+b
write (*,*) 'il risultato della somma a+b è', x
end program


Abbiamo anche il promemoria.
Cosa carina: nell'ultimo 'write' potremmo, di volta in volta, farci scrivere non 'a+b' ma la somma tra i numeri che noi abbiamo realmente digitato mettiamo, cioè, invece di "'il risultato della somma a+b è',x"


write(*,*) 'il risultato della somma', a, '+', b, 'è',x

Mi raccomando, ATTENZIONE! Tutto ciò che è scritto tra apici ('il risultato della somma ') o virgolette ("il risultato della somma "), il computer lo legge come testo (cosidetta stringa) mentre ciò che è lasciato fuori (a,b,x) come variabile.
Il tutto rigorosamente deve essere separato dalle virgole altrimenti fortran "sbrocca".
Seconda domanda: il computer sa chi sono a e b quando li legge? O meglio, sa che deve associarli a dei numeri? Prima di rispondere ricordatevi l' 'implicit none'.
Non lo sa. Quindi vanno dichiarati:

integer::a,b

Terza domanda: e se volessimo fargli sommare dei reali? Detto fatto.

real::a,b

Ma a questo punto 'x', cioè il risultato della loro somma, potrà essere intero? Eh no.

real::a,b,x

E 'integer::x' scompare.
Ora il nostro programmino è molto pulito:

Program nome programma
implicit none
real::a,b,x
write(*,*) 'inserisci due numeri a e b'
read (*,*), a,b
x=a+b
write (*,*) 'il risultato della somma a+b è', x
end program


Inseriamo al suo interno anche altre operazioni, tanto per imparare come si scrivono in fortran gli operatori matematici. Le scrivo e le commento affianco il comando relativo (i commenti in fortran sono preceduti dal punto esclamativo '!' e non vengono riconosciuti dal computer come linguaggio. Servono a noi come promemoria):

Program nome programma
implicit none
real::a,b,x
write(*,*) 'inserisci due numeri a e b'
read (*,*), a,b

x=a+b !addizione
y=a-b !sottrazione
z=a*b !moltiplicazione
v=a/b !divisione
p=a**2 !elevamento a potenza
r=sqrt(b) !radice quadrata

write (*,*) 'il risultato della somma',a,'+',b,'è', x
end program


Manca qualcosa? Direi di sì. Primo: dichiarazione delle variabili 'y,z,v,p,r' che saranno naturalmente reali. Secondo: vogliamo farcele scrivere.
Allora:

Program nome programma
implicit none
real::a,b,x,y,z,v,p,r
write(*,*) 'inserisci due numeri a e b'
read (*,*), a,b

x=a+b !addizione
y=a-b !sottrazione
z=a*b !moltiplicazione
v=a/b !divisione
p=a**2 !elevamento a potenza
r=sqrt(b) !radice quadrata

write (*,*) 'il risultato della somma',a,'+',b,'è', x
write (*,*) 'il risultato della sottrazione',a,'-',b,'è', y
write (*,*) 'il risultato della moltiplicazione',a,'*',b,'è', z
write(*,*)'il risultato della divisione',a,':',b,'è',v

write(*,*)'il quadrato di',a,'è',p
write(*,*)'la radice di',c,'é',r
end program

La fase di scrittura possiamo comprimerla un pò:

write(*,*) 'somma=',x,'sottrazione=',y,'moltiplicazione=',z,'divisione=',v, 'potenza di',a,'=',p,'radice di',b,'=',r

Quindi:

Program nome programma
implicit none
real::a,b,x,y,z,v,p,r
write(*,*) 'inserisci due numeri a e b'
read (*,*), a,b

x=a+b
y=a-b
z=a*b
v=a/b
p=a**2
r=sqrt(b)


write(*,*) 'somma=',x,'sottrazione=',y,'moltiplicazione=',z,'divisione=',v, 'potenza di',a,'=',p,'radice di',b,'=r'
end program

Arrivati a questo punto, dobbiamo fare un passo avanti.
Vogliamo sfruttare l'operazione somma per farci calcolare dal computer la serie di Fibonacci:

0,1,1,2,3,5,8,13,21,34,55...
Ogni numero è somma dei precedenti.
Ma per farlo ci vediamo alla prossima 'lezione'.

venerdì 19 novembre 2010

Programmazione..quale incubo! (fortran 1)

Primo passo: comunicare col computer.
Cosa avere accanto per iniziare a progammare:
- dispense del professore, eventuale manuale del programma o internet a portata di mano per cercare quelle spiegazioni che il professore mai vi darà;
- carta e penna;
- coscienza del fatto che lui è un computer, tu sei la mente e tu comandi su di lui...anche se all'inizio non sembrerà così;
- tanta, tanta, tanta pazienza ;).

Benissimo!
Il computer è una macchina, ed essendo tale se voi non gli specificate cosa deve fare lui semplicemente non lo fa o lo fa a modo suo.
Quindi è chiaro che dovremo dire al computer "Ehi, sto iniziando a scrivere il programma, d'ora in poi fai quello che ti dico". Ed ecco la prima istruzione fondamentale:

" Program nome programma "

"Nome programma" serve per fargli capire quale programma dei tanti state iniziando a scrivere.

Come comunicate l'inizio, dovete comunicare la fine del vostro programma perché altrimenti lui non ha idea di quando finirà l'operazione che voi volete faccia.
Perciò, consiglio: mettete subito

" Program nome programma "
" End program"

Dopodichè in mezzo aggiungiamo il resto.
Decidiamo di far fare al programma la somma 7+5.
Come glielo diciamo?
Se aveste un problema su carta in cui vi si chieda "Quanto fa 7+5", cosa scrivereste per risolverlo?
x=7+5 e quindi x=12
Usereste quindi una variabile.
Per il computer è uguale:

Program nome programma
x=7+5
End program

Bene! Se fate girare il programma cosa succede?
Il computer da errore. Perché?
Perché lui non ha mai visto 'x' prima e non si fida, vuole che gliela presentiamo e noi lo accontentiamo:

Program nome programma
integer::x
x=7+5
End program

Gli abbiamo detto che useremo una variabile intera (integer) che si chiama 'x'.
Facciamolo girare di nuovo. Ora non ci da errori ma finisce senza averci comunicato niente, perché il computer fa l'operazione ma non ha intenzione di dirci il risultato a meno che non glielo chiedete. Detto fatto:

Program nome programma
integer::x
x=7+5
write (*,*), x
End program

Cosa gli abbiamo chiesto? Scrivimi sullo schermo (il primo asterisco) in un formato standard cioè predefinito (secondo asterisco) x.
Ora facendo girare il programma, il computer ci parlerà e ci dirà il risultato.
Spesso, se gli facciamo fare tante operazioni, noi dimentichiamo quale dei risultati va a scrivere perciò potremmo aggiungere

write (*,*) 'il risultato della somma 7+5 è',x

L'output del nostro programma sarà:

il risultato della somma 7+5 è 12


Ultima considerazione per ora: ricordate che il computer ha al suo interno un enorme quantità di dati e delle quantità definite. Questo significa che a volte lui può confondersi e andarle ad usare anche dove non le vogliamo.
Per questo, subito dopo avergli detto "Ehi, sto iniziando", dobbiamo dirgli "Dimentica tutto quello che sai, ora decido io" e cioè

Program nome programma
implicit none
integer::x
x=7+5
write (*,*) 'il risultato della somma 7+5 è', x
End program

E se volessimo decidere di cambiare gli addendi di volta in volta?
Lo vedremo al prossimo passo
.

Programmazione..quale incubo!


Al contrario della maggior parte delle persone che parlano d'informatica e danno consigli informatici, io ho sempre odiato il computer ed ho imparato ad usarlo soltanto nel momento in cui è diventato strettamente necessario per il mio lavoro.
Devo dire che ho anche imparato ad apprezzarlo ed a divertirmi, anche se faccio ancora parte della categoria di persone che preferisce stampare le foto e leggere i libri su carta.
Proprio a causa del mio odio verso il computer e del fatto che le persone che hanno cercato di insegnarmi qualcosa di informatica ne sapevano sempre troppo per potermi realmente trasmettere qualcosa, ho trovato enormi difficoltà e gli esami di programmazione sono stati il mio incubo.
Grazie poi alla pazienza di quel genio informatico del mio ragazzo e alla mia testardaggine, oggi riesco a programmare, non dico meravigliosamente, ma dignitosamente. Tant'è che sto facendo da tutor a dei ragazzi della triennale in fisica.
E sono loro ad avermi fatto venire in mente l'idea di iniziare una specie di rubrica che provi ad insegnare a "non entrare nel panico davanti ad un foglio di programmazione vuoto". Quello che vorrei fare non è insegnare un linguaggio di programmazione ma usarne uno, fortran in questo caso perché a fisica si usa ancora fortran, per insegnare a ragionare e a capire come muoversi.
Spero in questo modo di dare un aiuto a tutti coloro che "non passerò mai l'esame di programmazione".