Informatica (CIV) Esercitazione su FORTRAN Andrea Romanoni [email protected] Dipartimento di Elettronica, Informazione e Bioingegneria Politecnico di Milano 3 dicembre 2013 Esercizio istogrammi Sequenza periodica Punti 3D e piani Confronto tra immagini Prefisso o Suffisso? Esercizio istogrammi Testo Si vuole scrivere un programma che legge da input i dati sulle precipitazioni di pioggia (in mm) durante i giorni di un anno, e stampa a video le precipitazioni totali (questa volta in cm) mese per mese. Più precisamente, il programma legge da tastiera (in ordine sparso) i dati sulle precipitazioni piovose (in mm) dei giorni dell’anno, secondo lo schema giorno mese mm, e calcola il totale delle precipitazioni per ogni mese dell’anno. In seguito, stampa a video un istogramma in cui, per ogni mese dell’anno, viene stampato un ’*’ per ogni cm di pioggia caduto in quel mese (per semplicità i mm vengono arrotondati al cm più vicino, per cui se, per esempio, nel mese di gennaio sono caduti in totale 46mm di pioggia, a video vengono stampati 5 ’*’). La stampa dell’istogramma può essere fatta in orizzontale (con i dati del mese di gennaio più a sinistra, e quelli del mese di dicembre più a destra), oppure in verticale (con i dati del mese di gennaio più in alto e quelli del mese di dicembre più in basso). Esercizio istogrammi Sequenza periodica Punti 3D e piani Confronto tra immagini Prefisso o Suffisso? Esercizio istogrammi Soluzione PROGRAM piogge IMPLICIT NONE #include <stdio.h> #include <stdlib.h> INTEGER, PARAMETER :: NumeroMesiAnno = 12 #define NUM_MESI_ANNO 12 typedef enum{true, false} boolean; CHARACTER(LEN=NumeroMesiAnno), & PARAMETER::InizialiNomiMesiAnno = & "GFMAMGLASOND" int main(int argc, char const *argv[]){ INTEGER, DIMENSION(NumeroMesiAnno) :: & PioggeMensiliMm, PioggeMensiliCm int piogge_mensili_mm[NUM_MESI_ANNO]; int piogge_mensili_cm[NUM_MESI_ANNO]; INTEGER :: Giorno, Mese, PioggiaMm LOGICAL :: InputTerminato INTEGER Indice, CmCorrente int giorno, mese, mm_pioggia; boolean input_terminato; int i, cm_corrente; char iniziali_nomi_mesi[] = "GFMAMGLASOND"; INTEGER :: NumAsterischi CHARACTER (LEN=MaxCmMese) :: Asterischi DO Indice = 1, NumeroMesiAnno PioggeMensiliMm(Indice) = 0 END DO for (i = 0; i < NUM_MESI_ANNO; ++i){ piogge_mensili_mm[i] = 0; } Esercizio istogrammi Sequenza periodica Punti 3D e piani Confronto tra immagini Prefisso o Suffisso? Esercizio istogrammi Soluzione InputTerminato = .FALSE. DO WHILE (.NOT. InputTerminato) WRITE (*,*) "Inserisci Giorno Mese mm" READ (*,*) Giorno, Mese, PioggiaMm IF (Giorno <= 0) THEN InputTerminato = .TRUE. ELSE PioggeMensiliMm(Mese) = & PioggeMensiliMm(Mese) + PioggiaMm END IF END DO !=====calcolo dei dati mensili arrotondati ===== CmCorrente = 0 DO Indice = 1, NumeroMesiAnno PioggeMensiliCm(Indice) = PioggeMensiliMm(Indice)/10 IF ((PioggeMensiliMm(Indice) - & PioggeMensiliCm(Indice)*10) >= 5) THEN input_terminato = false; do{ printf("Inserisci Giorno, Mese, mm\n"); scanf("%d %d %d", &giorno, &mese, &mm_pioggia)); if (giorno <= 0){ input_terminato = true; }else{ mese = mese - 1; piogge_mensili_mm[mese] = piogge_mensili_mm[mese] + mm_pioggia; } }while(input_terminato == false); cm_corrente = 0; for (i = 0; i < NUM_MESI_ANNO; ++i){ piogge_mensili_cm[i] = piogge_mensili_mm[i]/10; if ((piogge_mensili_mm[i] piogge_mensili_cm[i] * 10) >= 5){ piogge_mensili_cm[i] = piogge_mensili_cm[i] + 1; } PioggeMensiliCm(Indice)=PioggeMensiliCm(Indice)+1 END IF IF PioggeMensiliCm(Indice) > CmCorrente THEN CmCorrente = PioggeMensiliCm(Indice) END IF END DO if (piogge_mensili_cm[i] > cm_corrente){ cm_corrente = piogge_mensili_cm[i]; } } Esercizio istogrammi Sequenza periodica Punti 3D e piani Confronto tra immagini Prefisso o Suffisso? Esercizio istogrammi Soluzione !=====stampa dell’istogramma (orizzontale)===== WRITE (*,*) "" !va a capo DO WHILE (CmCorrente > 0) Asterischi = "" /*stampa l’istogramma (orizzontale)*/ while(cm_corrente > 0){ for (i = 0; i < NUM_MESI_ANNO; ++i){ if (piogge_mensili_cm[i] > cm_corrente){ printf(" * "); }else{ printf(" "); } } cm_corrente = cm_corrente - 1; printf("\n"); } /*stampa le lettere corrispondenti al mese*/ for (i = 0; i < NUM_MESI_ANNO; ++i){ printf(" %c ", iniziali_nomi_mesi[i]); } DO Indice = 1, NumeroMesiAnno IF (PioggeMensiliCm(Indice) <= CmCorrente) & THEN Asterischi(Indice:Indice) = ’*’ ELSE Asterischi(Indice:Indice) = ’ ’ END IF END DO WRITE (*,*) Asterischi CmCorrente = CmCorrente - 1 END DO WRITE (*,*) InizialiNomiMesiAnno END PROGRAM piogge return 0; } Esercizio istogrammi Sequenza periodica Punti 3D e piani Confronto tra immagini Prefisso o Suffisso? Sequenza periodica Testo Scrivere un programma che legge in ingresso una sequenza di al massimo 50 numeri interi strettamente positivi (>0), terminati dallo 0, e determina se la sequenza è “periodica”. In altre parole, il programma determina se c’è un valore P tale per cui i numeri si ripetono ogni P elementi della sequenza. Il programma deve anche stampare a video il periodo P. più piccolo. Esempi: La sequenza 3592359235920 è periodica di periodo 4. La sequenza 7813912830 non è periodica. La sequenza 38383838383838380 è periodica di periodo 2. La sequenza 444444444444444440 è periodica di periodo 1. Esercizio istogrammi Sequenza periodica Punti 3D e piani Confronto tra immagini Prefisso o Suffisso? Sequenza periodica Soluzione PROGRAM TrovaPeriodo IMPLICIT NONE INTEGER, DIMENSION(50) :: seq INTEGER :: n, p, i, n_el = 0 LOGICAL :: periodico WRITE (*,*) "Inserisci numero ", n_el + 1 READ (*,*) n DO WHILE (n_el < 50 .AND. n /= 0) n_el = n_el + 1 seq(n_el) = n WRITE (*,*) "Inserisci numero", n_el + 1 READ (*,*) n END DO IF (n_el == 0) THEN WRITE (*,*) "Nessun elemento inserito" ELSE IF (n_el <= 1) THEN WRITE (*,*) "Un solo elemento inserito,", & " il periodo e’ 1" ELSE p = 0 periodico = .FALSE. DO WHILE (.NOT. periodico .AND. p < n_el/2) p = p+1 IF ((n_el / p) * p == n_el) THEN periodico = .TRUE. i = 1 DO WHILE (periodico .AND. i <= n_el-p) IF (seq(i) /= seq(i+p)) THEN periodico = .FALSE. END IF i = i+1 END DO END IF END DO IF (periodico) THEN WRITE (*,*) "La sequenza e’ periodica ", & "di periodo ", p ELSE WRITE (*,*) "La sequenza non e’ periodica" END IF END IF END PROGRAM TrovaPeriodo Esercizio istogrammi Sequenza periodica Punti 3D e piani Confronto tra immagini Prefisso o Suffisso? Esercizio punti 3D e piani Testo A Scrivere un sottoprogramma che prende in ingresso una sequenza di punti dello spazio cartesiano tridimensionale a coordinate (x,y,z) intere, ed elimina dalla sequenza tutti quei punti che non si trovano su uno stesso piano orizzontale (cioè parallelo al piano (x.y)) con altri punti della sequenza. Per esempio, data la seguente sequenza di punti: <3,-2,8>, <-340,62,31>, <8,22,8>, <8,13,-12>, <54,-10,31>, <4,72,3> la sequenza viene modificata nel modo seguente: <3,-2,8>, <-340,62,31>, <8,22,8>, <54,-10,31> Esercizio istogrammi Sequenza periodica Punti 3D e piani Confronto tra immagini Prefisso o Suffisso? Esercizio punti 3D e piani Soluzione A SUBROUTINE EliminaPuntiIsolati(Sequenza, Num) IMPLICIT NONE TYPE (Punto), INTENT(INOUT), DIMENSION(Num) :: Sequenza INTEGER, INTENT(INOUT) :: Num INTEGER :: Cont1, Cont2 LOGICAL :: DaTenere TYPE :: Punto INTEGER :: X INTEGER :: Y INTEGER :: Z END TYPE Punto DO Cont1 1, Num DaTenere = .FALSE. DO Cont2 = 1, Num IF ( (Cont2 /= Cont1 ) .AND. & (Sequenza(Cont2)%Z == Sequenza(Cont1)%Z ) ) THEN DaTenere = .TRUE. END IF END DO IF (DaTenere .EQV. .TRUE.) THEN Cont1 = Cont1+1 ELSE DO Cont2 = Cont1, Num-1 Sequenza(Cont2) = Sequenza(Cont2+1) END DO Num = Num-1 END IF END DO END SUBROUTINE EliminaPuntiIsolati Esercizio istogrammi Sequenza periodica Punti 3D e piani Confronto tra immagini Prefisso o Suffisso? Esercizio punti 3D e piani Testo B Scrivere un sottoprogramma che prende in ingresso una sequenza di punti dello spazio cartesiano tridimensionale a coordinate intere, e partiziona la sequenza in sottoinsiemi in cui ogni sottoinsieme contiene tutti e soli i punti su uno stesso piano orizzontale (cioè parallelo al piano (x,y)). Il sottoprogramma, sfruttando anche il sottoprogramma definito nella parte a), restituisce una nuova sequenza di punti contenente i punti della sequenza originale raggruppati nei sottoinsiemi descritti sopra, esclusi però i sottoinsiemi fatti di un solo punto. I sottoinsiemi nella sequenza restituita possono essere in ordine qualunque. Per esempio, data la seguente sequenza di punti: <5,-2,7>, <-10,-92,3>, <84,2,7>, <8,10,2>, <52,-20,3>, <4,72,3> una possibile sequenza restituita è la seguente: <5,-2,7>, <84,2,7>, <-10,-92,3>, <52,-20,3>, <4,72,3> Esercizio istogrammi Sequenza periodica Punti 3D e piani Confronto tra immagini Esercizio punti 3D e piani Soluzione B SUBROUTINE RaggruppaPunti(SequenzaIn, NumIn, SequenzaOut, NumOut) IMPLICIT NONE TYPE (Punto), INTENT(INOUT), DIMENSION(NumIn) :: SequenzaIn TYPE (Punto), INTENT(OUT), DIMENSION(NumIn) :: SequenzaOut INTEGER, INTENT(IN) :: NumIn INTEGER, INTENT(OUT) :: NumOut INTEGER :: i LOGICAL :: Ordinato TYPE (Punto) :: temp SequenzaOut = SequenzaIn NumOut = NumIn CALL EliminaPuntiIsolati(SequenzaOut, NumOut) Ordinato = .FALSE. DO WHILE (Ordinato .EQV. .FALSE.) Ordinato = .TRUE. DO i=1,NumOut-1 IF(SequenzaOut(i)%Z > SequenzaOut(i+1)%Z) THEN Ordinato = .FALSE. temp = SequenzaOut(i) SequenzaOut(i) = SequenzaOut(i+1) SequenzaOut(i+1) = temp END IF END DO END DO END SUBROUTINE RaggruppaPunti Prefisso o Suffisso? Esercizio istogrammi Sequenza periodica Punti 3D e piani Confronto tra immagini Prefisso o Suffisso? Confronto tra immagini Testo Un’immagine è costituita da una matrice di 1024x1024 pixel. Ogni pixel è caratterizzato dal livello di intensità luminosa: tale livello è rappresentato da un intero. Una figura originale è costituita da una matrice di 25x25 pixel. Si vuole scrivere un sottoprogramma che, data un’immagine e data una figura originale, verifichi se la figura appare nell’immagine. Il sottoprogramma cerca occorrenze della figura nell’immagine, tenendo presente le seguenti sorgenti di variabilità: la figura potrebbe apparire non ruotata oppure ruotata di un angolo pari +90 gradi (cioè 90 gradi in senso antiorario), rispetto all’originale; a causa di eventuali variazioni (uniformi) di illuminazione, la figura potrebbe apparire nell’immagine con il livello di intensità di tutti i suoi pixel aumentati o diminuiti di un valore costante rispetto all’originale. Il sottoprogramma deve produrre in uscita la posizione e l’orientamento della figura nell’immagine, nel caso in cui la figura sia presente; in caso contrario deve produrre due coordinate negative (e un qualunque valore dell’angolo di rotazione). NB: Anche nel caso in cui la figura appaia più volte nell’immagine, il sottoprogramma deve produrre in uscita una sola occorrenza della figura. Esercizio istogrammi Sequenza periodica Punti 3D e piani Confronto tra immagini Prefisso o Suffisso? Confronto tra immagini Soluzione Cominciamo a definire una funzione che confronta due immagini e restituisce vero se sono uguali, o falso se sono differenti. LOGICAL FUNCTION ConfrontaMatrice(DimArray, Array1, Array2) IMPLICIT NONE INTEGER, INTENT(IN) :: DimArray INTEGER, DIMENSION (DimArray, DimArray), INTENT(IN) :: Array1, Array2 INTEGER :: X, Y LOGICAL, DIMENSION (DimArray, DimArray) :: ArrayConfronti ArrayConfronti = (Array1 == Array2) ConfrontaMatrice = .TRUE. DO X=1, DimArray DO Y=1, DimArray ConfrontaMatrice = ConfrontaMatrice .AND. ArrayConfronti(X,Y) END DO% END DO END FUNCTION ConfrontaMatrice Esercizio istogrammi Sequenza periodica Punti 3D e piani Confronto tra immagini Confronto tra immagini Soluzione SUBROUTINE CercaFigura(Immagine, Figura, PosX, PosY, Angolo) IMPLICIT NONE INTEGER, PARAMETER :: DimImmagine = 1024 INTEGER, PARAMETER :: DimFigura = 25 INTEGER, INTEGER, INTEGER, INTEGER, DIMENSION (DimImmagine, DimImmagine), INTENT(IN) :: Immagine DIMENSION (DimFigura, DimFigura), INTENT(IN) :: Figura INTENT(OUT) :: PosX, PosY INTENT(OUT) :: Angolo INTEGER, DIMENSION (DimFigura, DimFigura) :: FiguraRuotata INTEGER :: SpostY INTEGER :: Offset LOGICAL :: ConfrontaMatrice DO SpostY = 1, DimFigura FiguraRuotata(SpostY,:) = Figura(DimFigura:1:-1,SpostY) END DO Prefisso o Suffisso? Esercizio istogrammi Sequenza periodica Punti 3D e piani Confronto tra immagini Confronto tra immagini Soluzione DO PosX = 1, DimImmagine-DimFigura+1 DO PosY = 1, DimImmagine-DimFigura+1 Offset = Immagine(PosX, PosY) - Figura(1,1) IF(ConfrontaMatrice(DimFigura, & Immagine(PosX:PosX+DimFigura-1,PosY:PosY+DimFigura-1), & Figura(:,:) )) THEN Angolo = 0 RETURN END IF Offset = Immagine(PosX, PosY) - FiguraRuotata(1,1) IF (ConfrontaMatrice(DimFigura, & Immagine(PosX:PosX+DimFigura-1,PosY:PosY+DimFigura-1), & FiguraRuotata(:,:) + Offset)) THEN Angolo = 90 RETURN END IF END DO END DO PosX = -1 PosY = -1 END SUBROUTINE CercaFigura Prefisso o Suffisso? Esercizio istogrammi Sequenza periodica Punti 3D e piani Confronto tra immagini Prefisso o Suffisso? Prefisso o Suffisso? Testo Scrivere un programma che legge una sequenza di al massimo 100 caratteri alfabetici, terminati da un carattere non alfabetico, e determina se la sequenza ha un prefisso e un suffisso identici, cioè se la sequenza ha la stessa serie di caratteri al suo inizio e alla sua fine. Il programma NON distingue i caratteri maiuscoli da quelli minuscoli. Il programma stampa a video la sottosequenza ripetuta più lunga tra quelle esistenti. Esempi: La sequenza abCmpAbc6 è iniziata e terminata dalla stringa abc. Nella sequenza zazdazb& non c’è una sottosequenza che inizia e termina la stringa. La sequenza aBcDABcdabc è iniziata e terminata dalla stringa abcdabc. Esercizio istogrammi Sequenza periodica Punti 3D e piani Confronto tra immagini Prefisso o Suffisso? Nel computer i caratteri vengono rappresentati con dei numeri detti codici ASCII. Questa è la tabella di conversione: Esercizio istogrammi Sequenza periodica Punti 3D e piani Confronto tra immagini Prefisso o Suffisso? Prefisso o Suffisso? Soluzione PROGRAM PrefissoSuffisso IMPLICIT NONE ! salvo la lunghezza effettiva ! della stringa in lng lng = i - 1 CHARACTER (len = 100) :: sequenza INTEGER, PARAMETER :: offset = IACHAR(’A’) IACHAR(’a’) INTEGER :: lng, i LOGICAL :: trovato WRITE (*,*) "Inserire la sequenza:" READ (*,*) sequenza i = 1 DO WHILE (i <= LEN_TRIM(sequenza) .AND. ( (sequenza(i) >= ’a’ .AND. sequenza(i) <= ’z’) .OR. (sequenza(i) >= ’A’ .AND. sequenza(i) <= ’Z’) ) ) IF(sequenza(i) >= ’A’ .AND. & sequenza(i) <= ’Z’) THEN sequenza(i) =& ACHAR(IACHAR(sequenza(i)) - offset) END IF i = i+1 END DO & & & & trovato = .FALSE. i = lng - 1 DO WHILE (.NOT. trovato .AND. i > 0) IF (ALL(sequenza(1:i) == sequenza(lng-i+1:lng))) THEN trovato = .TRUE. ELSE i = i - 1 END IF END DO IF (trovato .EQV. .TRUE.) THEN WRITE (*,*) "La sequenza e’ iniziata", & "e terminata dalla stringa ", & sequenza(1:i) ELSE WRITE (*,*) "Non c’e’ sottosequenza ", & "che inizia e termina la stringa." END IF END PROGRAM PrefissoSuffisso