fortran
Transcript
fortran
UNINA2 – INGEGNERIA MECCANICA/AEROSPAZIALE ELEMENTI DI PROGRAMMAZIONE FORTRAN: LE STRUTTURE DI CONTROLLO Prof. Andrea Prevete - a.a. 2015/16 IF-THEN La più semplice struttura di controllo è lo statement IFTHEN. Un’espressione logica è valutata per consentire, se .TRUE., l’esecuzione di un definito blocco di istruzioni. LEXPR ? THEN (TRUE!) BLOCK IF-THEN Ecco la sintassi Fortran: IF (lexpr) THEN block END IF Oppure, se block è una singola istruzione, in formato single-line: IF (lexpr) istr Segue un segmento di programma che, letti due interi x ed y, immagazzina in una terza variabile il valore maggiore: INTEGER :: x, y, m READ(*,*) x, y m=x IF (y>m) THEN m=y END IF WRITE(*,*) m IF-THEN-ELSE ELSE (FALSE!) BLOCK2 LEXPR ? THEN (TRUE!) BLOCK1 Un’ immediata estensione della struttura di controllo IFTHEN è la IF-THEN-ELSE. Il valore di verità dell’espressione valutata seleziona, per l’esecuzione, uno fra due, alternativi, blocchi di istruzioni. IF-THEN-ELSE Ecco il codice Fortran: IF (lexpr) THEN block1 ELSE block2 END IF Segue la versione IF-THEN-ELSE del precedente segmento di programma: INTEGER :: x, y, m READ(*,*) x, y IF (x > y) THEN m=x ELSE m=y END IF WRITE(*,*) m ELSE-IF La forma più generale di costrutto IF disponibile in Fortran è la seguente: IF (lexpr1) THEN block-i ELSE IF (lexpr2) THEN block-1 …… ELSE IF (lexprn) THEN block-n ELSE block-e END IF Utilizzando questa forma di controllo si ha la possibilità di selezionare uno fra più blocchi di istruzioni da eseguire utilizzando una catena di espressioni logiche che restringono via via la scelta. ELSE-IF CHARACTER(10) :: Today, Oggi READ(*,*) Today IF (Today == “Monday”) THEN Oggi=“Lunedi” ELSEIF (Today == “Tuesday”) THEN Oggi=“Martedi” ELSEIF (Today == “Wednesday”) THEN Oggi=“Mercoledi” ELSEIF (Today == “Thursday”) THEN Oggi=“Giovedi” ELSEIF (Today == “Friday”) THEN Oggi=“Venedi” ELSEIF (Today == “Saturday”) THEN Oggi=“Sabato” ELSEIF (Today == “Sunday”) THEN Oggi=“Domenica” ELSE Oggi=“Errore!” ENDIF WRITE(*,*) Oggi SELECT-CASE Nei casi in cui la selezione fra più alternative è indirizzabile dai potenziali valori o insieme/range di valori che può assumere un’espressione intera/carattere/logica, il costrutto d’elezione reso disponibile dal Fortran è il SELECT-CASE: SELECT CASE (expr) CASE (selector-1) block-1 …… CASE (selector-n) block-n CASE DEFAULT block END SELECT E’ importante ricordare che i vari selettori rappresentano valori o gruppi/range di valori che devono mutuamente escludersi! SELECT-CASE Riscriviamo, ad esempio, il codice Fortran per tradurre in italiano il nome inglese di un giorno della settimana. E’ evidente la maggiore compattezza e leggibilità del risultato ottenuto! CHARACTER(10) :: Today, Oggi READ(*,*) Today SELECT CASE (Today) CASE (“Monday”) Oggi=“Lunedi” CASE (“Tuesday”) Oggi=“Martedi” CASE (“Wednesday”) Oggi=“Mercoledi” CASE (“Thursday”) Oggi=“Giovedi” CASE (“Friday”) Oggi=“Venedi” CASE (“Saturday”) Oggi=“Sabato” CASE (“Sunday”) Oggi=“Domenica” CASE DEFAULT Oggi=“Errore!” END SELECT WRITE(*,*) Oggi SELECT-CASE UN’ ALTRA SEMPLICE APPLICAZIONE PROGRAM calcolatrice IMPLICIT NONE ! ! INTEGER :: i,j,k CHARACTER :: Operatore DO WRITE(*,*) “Inserisci due interi: ” READ(*,*) i,j WRITE(*,*) “Quale operazione?: ” READ(*,*) Operatore SELECT CASE (Operatore) CASE ('+') K=I+J WRITE(*,*) ”La somma è: ”, K CASE ('-') K=I-J WRITE(*,*) “La differenza è: “, K CASE ('/‘,’:’) K=I/J WRITE(*,*) “Il quoziente è: “, K CASE ('*‘, ‘x’, ‘X’) K=I*J WRITE(*,*) “Il prodotto è. “, K CASE DEFAULT WRITE(*,*) “Operatore non valido! “ END SELECT END DO END PROGRAM calcolatrice UN’ APPLICAZIONE PIU’ COMPLESSA PROGRAM equaz2grado IMPLICIT NONE REAL :: a, b, c, d ! coefficienti ! dell’equazione e discriminante COMPLEX :: x1, x2 ! radici ! complesse dell’equazione ! lettura dei coefficienti WRITE(*,*) "Coefficiente a: " READ(*,*) a WRITE(*,*) "Coefficiente b: " READ(*,*) b WRITE(*,*) "Coefficiente c: " READ(*,*) c ! calcolo del discriminante d = b**2-4.*a*c IF (d > 0.) THEN PRINT*, "Radici reali e distinte" x1 = (-b-SQRT(d))/(2.*a) x2 = (-b+SQRT(d))/(2.*a) ELSE IF (d == 0.) THEN PRINT*, "Radici reali e coincidenti" x1 = -b/(2.*a) x2 = x1 ELSE PRINT*, "Radici complesse coniugate" x1 = CMPLX(-b,-SQRT(-d))/(2.*a) x2 = CONJG(x1) END IF WRITE(*,*) x1, x2 END PROGRAM equaz2grado Perché non possiamo usare SELECT CASE per scegliere fra le tre possibili soluzioni? CICLO CON CONTROLLO EX-ANTE Sintassi Fortran: DO WHILE (lexpr) block END DO Oppure: DO IF (.NOT. lexpr) EXIT block END DO CICLO CON CONTROLLO EX-ANTE PROGRAM costruisci_frase IMPLICIT NONE CHARACTER :: char CHARACTER(200)::str INTEGER :: i=0 WRITE(*,*) ‘Immetti un carattere (. per fine frase, # per spazio) :’ READ (*,*) char DO WHILE(char /= ’.’) i=i+1 IF (char == '#') char=' ' str(i:i) = char WRITE(*,*) ‘Immetti un carattere (. per fine frase, # per spazio) :’ READ (*,*) char END DO WRITE(*,*) ‘La frase immessa è: ’, str(1:i) END PROGRAM CICLO CON CONTROLLO EX-POST Sintassi Fortran: DO block IF (.NOT. lexpr) EXIT END DO CICLO CON CONTROLLO EX-POST PROGRAM temperatura ! Conversione temperatura fra diverse scale IMPLICIT NONE REAL :: T_c ! temperatura in gradi Celsius REAL :: T_k ! temperatura in Kelvin REAL :: T_f ! temperatura in gradi Fahrenheit REAL :: T_r ! temperatura in gradi Reaumur REAL :: dT ! incremento nella temperatura REAL, PARAMETER :: Tmin_c=0.0 ! temperatura di congelamento dell’acqua REAL, PARAMETER :: Tmax_c=100. ! temperatura di ebollizione dell’acqua REAL, PARAMETER :: cost=1.8 ! fattore 9/5 della convers. Cels->Fahr WRITE(*,*) "Incremento nella T: "; READ(*,*) dT WRITE(*,*) " Celsius Kelvin Fahrenheit Reaumur " WRITE(*,*) " ========== ========== =========== ========== " T_c = Tmin_c DO T_f = cost*T_c + 32. T_k = 273.15 + T_c T_r = 0.8*T_c WRITE(*,*) T_c, T_k, T_f, T_r T_c = T_c+dT IF (.NOT. (T_c <= Tmax_c)) EXIT ! i END DO END PROGRAM temperatura CICLO CON CONDIZIONE DI USCITA In realtà il ciclo DO del Fortran è un costrutto estremamente versatile che consente di implementare molte logiche di controllo. Per esempio, un ciclo con condizione di uscita in itinere, come quello in figura. Sintassi Fortran: DO block1 IF (lexpr) EXIT block2 END DO CICLO CON CONDIZIONE DI USCITA Riconsideriamo il codice visto per il ciclo con controllo ex-ante, apprezzandone la maggiore compattezza! PROGRAM costruisci_frase IMPLICIT NONE CHARACTER :: char CHARACTER(200)::str INTEGER :: i=0 DO WRITE(*,*) ‘Immetti un carattere(. per fine frase, # per spazio): ’ READ (*,*) char i=i+1 IF (char == ‘.’) EXIT ! Condizione di uscita IF (char == '#') char=' ' str(i:i) = char END DO WRITE(*,*) ‘La frase immessa è: ’, str(1:i) END PROGRAM CICLO CON CONTATORE Sintassi Fortran: DO i = inizio, fine [,passo] block END DO ATTENZIONE: - i è una variabile contatore di tipo INTEGER - inizio, fine ed opzionalmente passo (1 per default) sono espressioni di tipo INTEGER - Le variabili utilizzate per inizio, fine e passo non possono essere esplicitamente modificate dal blocco di istruzioni interne al ciclo. - NON si dovrebbe far fede sul valore assunto dalla variabile contatore a fine ciclo e, quindi, utilizzarla esplicitamente nel codice post-ciclo! CICLO CON CONTATORE PROGRAM SOMMA_DI_CUBI ! Stampa tutti i numeri a tre cifre ! pari alla somma dei cubi delle loro cifre IMPLICIT NONE INTEGER H, T, U DO H = 1, 9 ! Ciclo 1° livello DO T = 0, 9 ! Ciclo 2° livello DO U = 0, 9 ! Ciclo 3° livello IF (100*H + 10*T + U == H**3 + T**3 + U**3) THEN WRITE(*, "(3I1)“) H, T, U ENDIF END DO END DO END DO END SOMMA_DI_CUBI LO STATEMENT CYCLE PROGRAM DISPARI ! Conta il numero di naturali dispari immessi. ! Un numero negativo arresta la conta. ! Un numero pari forza una nuova iterazione. IMPLICIT NONE INTEGER :: numero, n_dispari=0 DO WRITE(*,*) “Immetti numero: " READ( *, *) numero IF (numero < 0) THEN EXIT IF (MODULO(numero, 2) == 0) CYCLE n_dispari = n_dispari + 1 END DO WRITE(*.*) “IL NUMERO DI DISPARI E’:", n_dispari END PROGRAM DISPARI