Il linguaggio Fortran 90: 2. Istruzioni di Controllo
Strutture di Controllo Programmi visti in precedenza permettono di eseguire le istruzioni solo nella sequenza indicata. La risoluzione di molti problemi richiede la scrittura di programmi in cui le azioni che si svolgono dipendono dall’input del problema. Strutture di controllo permettono di alterare la sequenza di esecuzione delle istruzione del programma al verificarsi di determinate condizioni. Due tipi fondamentali di istruzioni di controllo: Istruzioni Condizionali Cicli
Istruzioni Condizionali nome: IF (condizione) THEN istruzione 1 istruzione 2 END IF nome ________________________________ ELSE
Stampa del maggiore tra due interi !File: max.for !Scopo: primo esempio di istruzione condizionale(IF-THEN-ELSE) PROGRAM max ! Questo programma legge due numeri interi e stampa il maggiore IMPLICIT NONE INTEGER :: primo, secondo, maggiore WRITE (*,*) 'Inserisci due numeri interi, poi schiaccia il tasto RETURN' READ (*,*) primo, secondo IF (primo > secondo) THEN maggiore = primo ELSE maggiore = secondo END IF WRITE (*,*) 'Il maggiore dei due valori inseriti e'': ', maggiore STOP END PROGRAM max
Istruzioni condizionali nidificate. Le istruzioni condizionali possono essere a loro volta nidificate. Istruzione ELSE IF permette di realizzare IF annidati. nome: IF (condizione1) THEN istruzione 1 istruzione 2 ELSE IF (condizione2) THEN ELSE END IF nome
Classificazione dei Triangoli 1 ! File: triang1.for ! Scopo: applicazione degli IF annidati PROGRAM triangolo1 ! *** SEZIONE DICHIARATIVA *** ! IMPLICIT NONE REAL :: primo, secondo, terzo ! le lunghezze dei tre lati ! *** SEZIONE ESECUTIVA *** ! WRITE (*,*) 'Inserisci le lunghezze dei tre lati del triangolo: ' READ (*,*) primo,secondo,terzo
Classificazione dei Triangoli 1 (cont.) if1: IF (primo == secondo) THEN if2: IF (secondo == terzo) THEN WRITE (*,*) 'Equilatero' ! I tre lati sono sono uguali fra loro ELSE WRITE (*,*) 'Isoscele' ! 1 coppia di lati uguali fra loro END IF if2 if3: IF (secondo == terzo) THEN ! primo <> secondo ELSE IF (primo == terzo) THEN ! (primo <> secondo) e (secondo <> terzo) WRITE (*,*) 'Scaleno' ! 0 coppie di lati uguali fra loro END IF if3 END IF if1 STOP END PROGRAM triangolo1
Classificazione dei Triangoli 2 Il programma può essere semplificato scegliendo un diverso algoritmo di soluzione If logico: IF (condizione) istruzione ! File: triang2.for PROGRAM triangolo2 ! *** SEZIONE DICHIARATIVA *** ! IMPLICIT NONE REAL :: primo, secondo, terzo INTEGER :: uguali ! il numero di coppie di lati uguali fra loro
Classificazione dei Triangoli 2 ! *** SEZIONE ESECUTIVA *** ! WRITE (*,*) 'Inserisci le lunghezze dei tre lati del triangolo: ' READ (*,*) primo,secondo,terzo uguali = 0 IF (primo == secondo) uguali = uguali + 1 IF (secondo == terzo) uguali = uguali + 1 IF (primo == terzo) uguali = uguali + 1 IF (uguali == 0) THEN WRITE (*,*) 'Scaleno' ELSE IF (uguali == 1) THEN WRITE (*,*) 'Isoscele' ELSE WRITE (*,*) 'Equilatero' END IF STOP END PROGRAM triangolo2
Espressioni Logiche Le condizioni sono espressioni logiche, possono assumere due valori di verità. Costanti logiche: .TRUE. o .FALSE. Variabili logiche: LOGICAL :: variabile_logica Operatori relazionali ==, /=, >, >=, <, <= Es: (7 + 3) /= 6 .TRUE.
Operatori Logici x .AND. y: .TRUE. sse x e y sono .TRUE. (altrimenti .FALSE.) x .OR. y: .TRUE. sse x o y sono .TRUE. x .EQV. y: .TRUE. sse x = y x .NEQV. y: .TRUE. sse x /= y .NOT. y: .TRUE. sse y = .FALSE. Es: LOGICAL :: x, y, z x = .TRUE. y = .FALSE. z = (x .OR. y) .AND. (x .NEQV. y) .AND. (x /= y) = .TRUE.
Regole di precedenza tra operatori logici Operatori aritmetici Operatori relazionali da sx a dx Operatori .NOT. da sx a dx Operatori .AND. da sx a dx Operatori .OR. da sx a dx Operatori .EQV. e . NEQV. da sx a dx
Classificazione di triangoli 3 ! File: triang3.for PROGRAM triangolo3 IMPLICIT NONE REAL :: primo, secondo, terzo ! le lunghezze dei tre lati WRITE (*,*) 'Inserisci le lunghezze dei tre lati del triangolo: ' READ (*,*) primo,secondo,terzo IF (primo == secondo .AND. secondo == terzo) THEN WRITE (*,*) 'Equilatero' ELSE IF (primo == secondo .OR. secondo == terzo .OR. primo == terzo) THEN WRITE (*,*) 'Isoscele' ELSE WRITE (*,*) 'Scaleno' END IF STOP END PROGRAM triangolo3
Calcolo delle radici di un’equazione di secondo grado !File: radici.for PROGRAM radici !Scopo: Questo programma calcola le radici di un’equazione ! a*x**2+ b*x + c = 0 ! *** SEZIONE DICHIARATIVA *** ! IMPLICIT NONE REAL :: a, b, c REAL :: discriminante, parte_immag, parte_reale REAL :: x1, x2 ! Soluzioni dell’equazione ! *** SEZIONE ESECUTIVA *** ! WRITE (*,*) 'Inserire i tre coeefficienti A, B e C: ' READ (*,*) a, b, c !Calcola il discriminante discriminante = b**2 - 4 * a * c
Calcolo delle radici di un’equazione di secondo grado (cont) ! Calcola le radici in funzione del discriminante IF (discriminante >0) THEN ! due radici reali x1 = (-b + sqrt(discriminante)) / (2.*a) x2 = (-b - sqrt(discriminante)) / (2.*a) WRITE (*,*) 'Due radici reali: ', x1, x2 ELSE IF (discriminante == 0.) THEN ! Radici reali e coincindenti x1 = ( -b ) / (2. * a) WRITE (*,*) 'due radici reali e coincidenti: ', x1 ELSE ! Radici complesse parte_reale = ( -b ) / (2. * a) parte_immag = sqrt(abs(discriminante)) / (2.*a) WRITE (*,*) 'due radici immaginarie:', parte_reale, '+/- i', parte_immag END IF STOP END PROGRAM radici
L’istruzione Case nome: SELECT CASE (espressione) CASE (sel 1)! Se espressione nel ! range di sel 1 istruzione 1 CASE (sel 2) ! Se espressione nel ! range di sel 2 istruzione 2 .. CASE DEFAULT ! In tutti gli altri casi istruzione END SELECT nome
Calcolo della data del giorno successivo !File: datasuc1.for !Scopo: esempio di uso dell’istruzione CASE PROGRAM data_successiva ! Questo programma legge giorno, mese ed anno di una data e determina ! la data successiva. Date possibili in ingresso: 1/1/1900 - 30/12/2000 ! *** SEZIONE DICHIARATIVA *** ! IMPLICIT NONE INTEGER :: giorno, mese, anno ! dati in input INTEGER :: giorni_del_mese ! dato da calcolare ! *** SEZIONE ESECUTIVA *** ! WRITE (*,*) 'Data (giorno, mese, anno)? ' READ (*,*) giorno, mese, anno WRITE (*,*) 'Il giorno successivo al', giorno, '/', mese, '/', anno, ' e'':' SELECT CASE (mese) CASE (9,4,6,11) giorni_del_mese = 30 CASE (1,3,5,7,8,10,12) giorni_del_mese = 31
Calcolo della data del giorno successivo (cont.) CASE (2) IF (MOD(anno,4) == 0 .AND. anno /= 1900) THEN giorni_del_mese = 29 ELSE giorni_del_mese = 28 END IF END SELECT ultimo: IF (giorno == giorni_del_mese) THEN giorno = 1 dicembre: IF (mese == 12) THEN mese = 1 anno = anno + 1 mese = mese + 1 END IF dicembre giorno = giorno + 1 END IF ultimo WRITE (*,*) giorno, '/', mese, '/', anno STOP END PROGRAM data_successiva
Istruzioni di Ciclo Permettono di ripetere un insieme di istruzioni finchè una certa condizione si verifica. Cicli indefiniti: Il numero di ripetizioni non è noto in anticipo Cicli definiti o iterativi: Il numero di ripetizioni è noto prima dell’inizio del ciclo.
Cicli indefiniti: Ciclo WHILE DO istruzione 1 IF (espressione logica) EXIT istruzione 2 END DO Quando la condizione di fine ciclo è vera, il controllo passa all’istruzione successiva a END DO. istruzione 1 viene eseguita almeno una volta.
Calcolo della lunghezza di una sequenza di interi Calcola la lunghezza di una sequenza di interi positivi terminati da uno 0 Gli interi sono letti in input uno ad uno finchè l’utente non indica lo 0
Calcolo della lunghezza di una sequenza di interi (cont.) ! File: lung.for ! Scopo: primo esempio di uso di un ciclo di iterazione indefinita PROGRAM calcola_lunghezza IMPLICIT NONE INTEGER :: lunghezza !la lunghezza della sequenza INTEGER :: dato ! il dato letto in input WRITE(*,*) 'Inserisci una sequenza di interi, terminata da 0: ' lunghezza = 0 ! all'inizio la lunghezza e' inizializzata a 0 DO ! iterazione indefinita READ (*,*) dato IF (dato == 0) EXIT ! condizione di uscita dal ciclo lunghezza = lunghezza + 1 END DO WRITE(*,*) 'La sequenza (senza lo 0 finale) e'' lunga ',lunghezza STOP END PROGRAM calcola_lunghezza
Calcolo del Massimo Comun Divisore ! File: mcd1.for PROGRAM massimo_comun_divisore ! Questo programma legge due numeri interi a, b positivi e ne calcola ! il massimo comun divisore. ! *** SEZIONE DICHIARATIVA *** ! IMPLICIT NONE INTEGER :: a, b ! dati letti da tastiera INTEGER :: mcd ! massimo comun divisore LOGICAL :: trovato ! *** SEZIONE ESECUTIVA *** ! WRITE (*,*) 'Inserisci due interi positivi: ' READ (*,*) a, b IF (a <= b) THEN mcd = a ELSE mcd = b END IF trovato = .FALSE.
Calcolo del Massimo Comun Divisore (cont.) DO IF (mcd == 1 .OR. trovato) EXIT IF (MOD(a,mcd) == 0 .AND. MOD(b,mcd) == 0) THEN trovato = .TRUE. ELSE mcd = mcd - 1 END IF END DO WRITE (*,*) 'Massimo comun divisore di ', a, ' e ', b, ' : ', mcd STOP END PROGRAM massimo_comun_divisore
Calcolo della Media e della Varianza n numeri reali x1,…., xn. Media: Varianza:
Calcolo della Media e della Varianza (cont.) ! File: stat.for PROGRAM media_varianza ! Questo programma calcola la media e la varianza di un insieme di ! dati positivi o nulli forniti in input ! *** SEZIONE DICHIARATIVA *** ! IMPLICIT NONE INTEGER :: n=0 ! Numero di dati letti in input REAL :: std_dev = 0 ! Deviazione standard REAL :: sum_x = 0 ! Somma dei dati REAL :: sum_x2 = 0 ! Somma dei quadrati dei dati REAL :: x ! Dato in input REAL :: x_bar ! Media dei dati
Calcolo della Media e della Varianza (cont.) ! *** SEZIONE ESECUTIVA *** ! DO WRITE (*,*) 'Digita il numero: (num<0 per uscire) ' READ (*,*) x WRITE (*,*) 'Il numero e'':', x IF (x < 0) EXIT ! Calcola le Somme n = n + 1 sum_x = sum_x + x sum_x2 = sum_x2 + x**2 END DO
Calcolo della Media e della Varianza (cont.) ! Controlla che i dati di input siano sufficienti IF (n < 2) THEN WRITE (*,*) 'Bisogna immettere almeno due valori.' ELSE x_bar = sum_x / real(n) std_dev = sqrt ((real(n) * sum_x2 - sum_x**2) / (real(n) * real(n-1))) WRITE (*,*) 'La media di questo insieme e'':', x_bar WRITE (*,*) 'La deviazione standard e'':', std_dev WRITE (*,*) 'Il numero dei dati in input e'':', n END IF STOP END PROGRAM media_varianza
Cicli Annidati All’interno di un’istruzione di ciclo si possono eseguire altre istruzioni di ciclo E’ possibile associare un nome ad un ciclo: nome: DO ….. IF (espressione logica ) EXIT nome END DO nome
Numeri perfetti Un numero perfetto è un numero somma di tutti i suoi divisori ad esclusione del numero stesso. Es: 6 = 1 + 2 + 3 Per ogni intero positivo in input viene verificato se il numero è perfetto Il ciclo DO esterno legge i dati in input, il ciclo DO interno verifica se il numero è perfetto.
Numeri Perfetti (cont.) ! File: perfetto.for PROGRAM perfetto ! Questo programma determina se ogni intero positivo letto in input è ! perfetto ! *** SEZIONE DICHIARATIVA *** ! IMPLICIT NONE INTEGER :: dato ! dato in input INTEGER :: somma = 1 ! somma dei divisori INTEGER :: i = 2 ! potenziale divisore; si parte da 2 ! *** SEZIONE ESECUTIVA *** ! !leggi: DO WRITE (*,*) 'Inserisci valore (val <= 0 per uscire): ' READ (*,*) dato IF (dato <= 0) EXIT leggi WRITE(*,*) 'Divisori di', dato, ' (oltre a 1):'
Numeri Perfetti (cont.) verifica: DO IF (MOD(dato,i) == 0) THEN IF (dato == i*i) THEN WRITE (*,*) i somma = somma + i ELSE WRITE (*,*) i, dato / i somma = somma + i + dato / i END IF i = i + 1 IF (i*i > dato) EXIT verifica END DO verifica IF (somma == dato) THEN WRITE (*,*) dato, ' E'' UN NUMERO PERFETTO' WRITE (*,*) dato, ' non e'' un numero perfetto' END DO leggi STOP END PROGRAM perfetto
Cicli definiti: Ciclo DO Il numero di iterazioni è noto prima dell’esecuzione dell’istruzione di ciclo DO indice = inizio, fine, incremento istruzione 1 ……. istruzione 2 END DO
Ciclo DO (cont.) inizio, fine, incremento: sono espressioni calcolate prima dell’inizio del ciclo All’inizio: indice = inizio Le istruzioni del corpo del ciclo sono eseguite se: abs(indice) <= abs(fine) Dopo l’esecuzione delle istruzioni del ciclo: indice = indice + incremento
Ciclo DO (Cont.) DO i = 1, 10, 2 istruzione 1 istruzione n END DO Il corpo del ciclo eseguito 5 volte DO i = 3, -3, -2 Il corpo del ciclo eseguito 4 volte
Calcolo del Fattoriale ! File: fatt.for ! Scopo del programma è illustrare l’uso di cicli definiti PROGRAM fatt ! Calcola il fattoriale di un intero IMPLICIT NONE INTEGER :: n, i , fattoriale ! Variabili che indicano l’intero, l’indice del ciclo ed il fattoriale WRITE (*,*) 'Inserisci un intero: ' READ (*,*) n fattoriale = 1 DO i=2, n fattoriale = fattoriale * i END DO WRITE (*,*) 'Il fattoriale di', n, ' e'':', fattoriale STOP END PROGRAM fatt
Stampa di un Quadrato ! File: quadrato.for ! Scopo: illustrazione di un esercizio con cicli e stringhe PROGRAM quadrato ! Questo programma legge un numero intero positivo n da tastiera e ! stampa un quadrato di asterischi di dimensione n ! *** SEZIONE DICHIARATIVA *** ! IMPLICIT NONE INTEGER, PARAMETER :: max_lunghezza = 25 ! lunghezza massima del lato INTEGER :: n ! dato letto da tastiera INTEGER :: i ! indice dei cicli CHARACTER(max_lunghezza) :: linea ! linea da stampare
Stampa di un Quadrato (cont.) ! *** SEZIONE ESECUTIVA *** ! WRITE (*,*) 'Dimensione del lato (lmin=1, lmax=25): ' READ (*,*) n IF (n < 1 .OR. n > 25) THEN WRITE (*,*) n, ' e'' un input non valido.' ELSE DO i = 1, n linea(i:i) = '*' END DO DO i = n+1, max_lunghezza linea(i:i) = ' ' WRITE (*,*) linea END IF STOP END PROGRAM quadrato
Cicli DO annidati: Calcolo della Tavola Pitagorica ! File: tavolpit.for ! Scopo: illustrare un programma con cicli annidati PROGRAM tavola_pitagorica ! Questo programma legge un numero intero positivo n da tastiera e ! stampa tutti i prodotti i * j (1 <= i,j <= n), uno per riga IMPLICIT NONE INTEGER :: n ! il dato letto da tastiera INTEGER :: i,j ! indici dei cicli WRITE (*,*) 'Inserisci un intero positivo: ' READ (*,*) n WRITE (*,*) 'Tavola pitagorica da 1 a ', n, ': ' esterno: DO i = 1, n interno: DO j = 1, n WRITE (*,*) i, ' * ', j, ' = ', i*j END DO interno END DO esterno STOP END PROGRAM tavola_pitagorica
Traiettoria di un proiettile Traiettoria parabolica di un proiettile sparato con velocità iniziale v0 e angolo theta dalla posizione (0,0) vx = v0 * COS(theta) vy = v0 * SIN(theta) Altezza dal suolo al tempo t: y(t) = vy * t + 1/2 * g * t**2 Distanza orizzontale percorsa al tempo t x(t) = vx * t Data la velocità v0, determinare: la gittata (distanza orizzontale del proiettile prima di toccare terra) al variare di theta tra 0° e 90° con step di 1°. l’angolo theta per cui la gittata è massima.
Calcolo della gittata Tempo di atterraggio: vy * t + 1/2 * g * t**2 = 0 t1 = 0, t2 = - 2 * vy / g range = vx t2 = - 2 * vx * vy / g = - 2 v0**2 * COS(theta) * SIN(theta) /g
Traiettoria di un proiettile (cont.) ! File: gittata.for PROGRAM gittata ! Scopo: Calcolare la distanza percorsa da un proiettile sparato con ! angolo theta e velocità v = 20 m/s ! *** SEZIONE DICHIARATIVA *** ! IMPLICIT NONE REAL, PARAMETER :: gradi_a_rad = 0.01745329 ! Conversione da gradi a radianti REAL, PARAMETER :: gravity = -9.81 INTEGER :: max_degrees ! Angolo di massima gittata REAL :: max_range ! Massima gittata alla velocita’ v0 REAL :: range ! Gittata con un dato angolo REAL :: radian ! Angolo iniziale in radianti INTEGER :: theta ! Angolo iniziale in gradi REAL :: v0 ! Velocita’ del proiettile
Traiettoria di un proiettile (cont.) ! *** SEZIONE ESECUTIVA *** ! max_range = 0. max_degrees = 0 v0 = 20. loop: DO theta = 0, 90 radian = real(theta) * gradi_a_rad range = - 2. * v0**2 * COS(radian) * SIN(radian) / gravity WRITE (*,*) 'THETA =', theta, ' gradi; Gittata =', range, ' metri' IF (range > max_range) THEN max_range = range max_degrees = theta END IF END DO loop WRITE (*,*) 'Gittata massima = ', max_range, ' a', max_degrees, ' gradi' STOP END PROGRAM gittata
Esercizi Scrivere un programma che calcoli il massimo di una sequenza di interi positivi dati in input e terminati da uno 0. Scrivere un programma che dato in input un intero n stampi un triangolo equilatero di asterischi. Ad esempio per n=5: * * * * * * * * * * * * * * * Disegnare la traiettoria di un proiettile sul piano cartesiano