User Tools

Site Tools


appunti3s:python_e_strutture_di_controllo

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
appunti3s:python_e_strutture_di_controllo [2018/10/18 21:55] profproappunti3s:python_e_strutture_di_controllo [2020/06/08 22:19] (current) – external edit 127.0.0.1
Line 1: Line 1:
 +
 +====== Strutture di controllo ======
 +
 +>> indice: [[appunti3s:linguaggio_python]]
 +
 +===== Introduzione =====
 +
 +Quando si affronta la programmazione si devono indicare al computer delle istruzioni da eseguire.
 +Se il computer potesse comprendere il linguaggio naturale, sarebbe facile chiedere:
 +  * di eseguire un'istruzione //condizionale//: se questo è vero, fai una cosa, altrimenti fai quest'altra cosa;
 +  * di eseguire un'istruzione //iterativa//: ripeti questo per 100 volte;
 +  * di eseguire una //sequenza// di istruzioni: fai prima questo, poi fai questo e poi quest'altro.
 +
 +Si tratta di istruzioni per noi molto semplici da comprendere, ma che devono essere espresse in modo da poter essere comprese dal computer.
 +Ognuna delle precedenti istruzioni è un esempio di: una condizione, un'iterazione e una sequenza. 
 +
 +=====Teorema Böhm-Jacopini=====
 +
 +Questo teorema afferma che qualsiasi //algoritmo// può essere descritto utilizzando solo **tre** tipi di strutture: la sequenziale, la condizionale e l'iterativa.
 +
 +Gli esempi appena visti erano proprio di queste strutture:
 +
 +{{:appunti3s:strutture.png?|}}
 +
 +I programmi che seguiranno sono privi di altre funzioni oltre al main() per mettere in evidenza solo queste tre strutture. Al loro fianco sarà presente un diagramma di flusso che usa gli stessi colori per mettere in evidenza le tre strutture.
 +
 +Le tre strutture possono anche essere combinate insieme tra di loro: si può inserire una struttura sequenziale all'interno di una condizionale(Figura 1), oppure una struttura condizionale dentro una struttura iterativa (Figura 2).
 +{{ :appunti3s:multistruttura.png |}}
 +In Python l'inserimento di una struttura dentro un'altra si ottiene aumentando l'indentazione, cioè spostando un testo di quattro spazi più a destra, ad esempio:
 +<code>
 +struttura-esterna
 +struttura-esterna
 +    struttura-interna
 +    struttura-interna
 +            struttura-piu'-interna
 +struttura-esterna
 +struttura-esterna
 +</code>
 +===== Traduzione  =====
 +
 +Poiché queste tre strutture sono indispensabili per descrivere tutti gli algoritmi, ogni linguaggio di programmazione consente di tradurle come istruzioni. Nei prossimi esempi si vedrà che 
 +  * La struttura sequenziale si traduce in Python scrivendo una sequenza di istruzioni, in fila e ben allineate verticalmente, con la stessa indentazione:
 +    * <code>
 +istruz.1
 +
 +istruz.5
 +</code>
 +
 +  * La struttura condizionale si traduce in Python usando un'istruzione //if// ed eventualmente //else:// (attenzione all'indentazione di alcune righe)
 +    * <code>
 +if … :
 +    …
 +else :
 +    …
 +</code>
 +
 +  * La struttura iterativa //precondizionale// in Python si può tradurre in due modi diversi, tra loro equivalenti, usando //while// oppure //for// (attenzione all'indentazione di alcune righe)
 +    * <code> while … :
 +       …
 +</code>  
 +    * <code>for … in … :
 +       …
 +</code>
 +
 +=====Struttura sequenziale=====
 +
 +Un programma può eseguire una lista sequenziale di istruzioni{{ :appunti3s:cpp31.png?200|}}
 +  * //Esempio che calcola l'area di un cerchio//
 +  * chiedere in input un valore per il raggio
 +  * calcola l'area di un cerchio (formula…)
 +  * visualizzare in output l'area
 +
 +^ var. di input ^ tipo ^ var. di output ^ tipo ^ var. di lavoro ^ tipo ^
 +| raggio | num. virgola | area | num. virgola | area | num. virgola |
 +
 +>> La struttura sequenziale si traduce in Python con una lista ben allineata, perché in Python l'indentazione viene usata proprio per segnare la struttura della sequenza
 +<code>
 +istruz.1
 +
 +istruz.5
 +</code>
 +<file python 30.py>
 +raggio = float(raw_input("Inserisci il valore del raggio del cerchio:\n"))
 +area = raggio*raggio*3.14
 +print "L'area del cerchio vale:", area
 +</file>
 +
 +=====Struttura condizionale=====
 +
 +Un programma può eseguire istruzioni diverse in base al verificarsi di una condizione
 +{{ :appunti3s:cppmaggiorenne.png?250|}}
 +  * //Esempio che visualizza la maggiore età//
 +  * chiedere in input il valore dell'anno di nascita
 +  * calcolare l'età attuale
 +  * se età < 18
 +    * allora visualizzare in output: sei minorenne
 +    * altrimenti visualizzare in output: sei maggiorenne
 +
 +^ costanti ^ valore ^ var. di input ^ tipo ^ var. di output ^ tipo ^ var. di lavoro ^ tipo ^
 +| annoAttuale | 2012 | annoNascita | intero | - | - | - | - |
 +
 +>> La struttura condizionale si traduce in Python indicando la condizione dentro il rombo dentro un'istruzione //if :// che contiene la condizione logica da verificare. Dopo si scrive l'istruzione  (o le istruzioni) da eseguire nel caso "vero". Poi, nell'eventualità che vi siano istruzioni nel caso "falso", si scrive anche //else:// e dopo le sue eventuali istruzioni.
 +<code>
 +if …:
 +    …
 +else:
 +    …
 +</code>
 +
 +
 +<file python 31.py>
 +annoAttuale=2012;
 +annoNascita = int(raw_input("Per favore scrivi l'anno di nascita:\n"))
 +if annoAttuale-annoNascita < 18 :
 +    print "Minorenne."
 +else:
 +    print "Maggiorenne."
 +</file>
 +
 +====Operatori logici====
 +L'algebra di Bool (booleana) è un'algebra nata per definire la logica delle //proposizioni//, dove si studia lo stato (il valore) di verità delle proposizioni. Una proposizione può essere //vera// oppure //falsa//
 +
 +ATTENZIONE: non confondere in italiano il termine //proposizione// con //preposizione//, che ha un altro significato…
 +
 +Esempio di proposizione (con valore tra parentesi):
 +  * P = "il quadrato ha 4 lati" (vero)
 +  * Q = "il tuo cane miagola" (falso)
 +
 +In tale algebra esistono diversi operatori (detti operatori booleani oppure connettivi logici) che possono essere applicati ad una o più proposizioni.
 +  * AND (detto congiunzione)
 +  * OR (detto disgiunzione)
 +  * NOT (detto negazione)
 +  * altri meno famosi come: NAND, NOR, XOR,...
 +
 +=== Esempio di NOT ===
 +
 +Applicando l'operatore NOT alle due precedenti proposizioni il loro valore di verità diventa l'opposto:
 +  * NOT P = "il quadrato NON ha 4 lati" (falso)
 +  * NOT Q = "il tuo cane NON miagola" (vero)
 + 
 +=== Esempio di AND ===
 +
 +Applicando l'operatore AND, si ottiene una nuova proposizione il cui valore di verità dipende dalla verità di entrambe le proposizioni di partenza (è vera solo se sono entrambe vere)
 +  * P AND Q = "il quadrato ha 4 lati" E "il tuo cane miagola" (falso)
 +
 +=== Esempio di OR ===
 +
 +Applicando l'operatore OR, si ottiene una nuova proposizione il cui valore di verità dipende dalla verità di entrambe le proposizioni di partenza (è vera se almeno una delle due è vera):
 +  * P OR Q = "il quadrato ha 4 lati" OPPURE "il tuo cane miagola" (vero)
 +
 +=== La tabella di verità ===
 +
 +Per ogni operatore booleano (AND, OR, NOT, ecc.) si può costruire una tabella che aiuta a descriverlo. 
 +Nella seguente tabella sono messe a confronto gli operatori AND e OR. Le prime due colonne sono due proposizioni su cui applicare tali operatori.
 +
 +^ P ^ Q ^P AND Q^P OR Q^
 +| V | V |  V  |  V  |
 +| V | F |  F  |  V  |
 +| F | V |  F  |  V  |
 +| F | F |  F  |  F  |
 +
 +La tabella di verità del NOT è più semplice:
 +
 +^ P ^ NOT P ^
 +| V | F |
 +| F | V |
 +
 +===Il calcolo automatico===
 +
 +Di solito gli operatori logici possono essere usati anche dall'elaboratore.
 +Poiché l'elaboratore utilizza il sistema di numerazione in base 2, al valore Vero viene fatto corrispondere il valore //1// mentre al Falso lo //0//. Più in generale qualsiasi valore diverso da //0// è considerato vero.
 +In aggiunta a questo tipo di convenzione, il linguaggio C++ permette di usare variabili di un tipo specifico per le espressioni booleane, il tipo //bool//, e che possono valere: //false// o //true//.
 +In quasi tutti i linguaggi di programmazione il numero intero ZERO viene interpretato come False. Qualsiasi altro numero come True. 
 +Inoltre ci sono espressioni di confronto come //a < b// o come //x != 0// che hanno un risultato True oppure False, e alle quali possono essere applicati i precedenti operatori logici.
 +Il calcolo automatico di queste espressioni (come //a < b//) permette al programma di eseguire un'istruzione oppure un'altra a seconda se l'espressione venga valutata vera oppure falsa.
 +
 +=== Traduzione in Python===
 +Nel linguaggio Python gli operatori logici AND, OR e NOT vengono tradotti con le seguenti parole chiave:
 +^operatore^simbolo^
 +| AND | and |
 +| OR | or |
 +| NOT | not |
 +
 +Per l'ordine di precedenza vedere[[appunti3s:programmazione_imperativa#operazioni_su_int]]
 +{{ :appunti3s:nebbia.png?160|}}
 +  * Esempio di algoritmo che prevede la presenza di nebbia quando si verificano le seguenti condizioni: umidità relativa compresa tra il 85% e il 90%. 
 +  * chiedere in input il valore di umidità relativa (massimo 100)
 +  * se //umidita// > 85 && //umidita// < 90
 +    * allora visualizzare in output "previsione di nebbia"
 +    * altrimenti visualizzare in output "non si prevede nebbia"
 +<file python 32b.py>
 +#Domanda: cosa accade se inserisco un valore negativo?
 +umiditaMin=85
 +umiditaMax=90
 +umidita = int(raw_input("Scrivi il valore di umidita' relativa, come intero da 0 a 100.\n"))
 +if umidita > umiditaMin and umidita < umiditaMax : # attenzione alla precedenza degli operatori...
 +    print "si prevede nebbia"
 +else:
 +    print " non si prevede nebbia "
 +</file>
 +
 +====Struttura condizionale annidata====
 +Nella struttura condizionale annidata è consentito l'uso di //elif … :// (che unisce else con if). La soluzione di questo esercizio viene fornita sia con elif che senza elif.
 +{{ :appunti3s:cpp33.png?250|}}
 +  * //Esempio che visualizza il minimo di tre numeri//
 +  * chiedere in input 3 valori numerici interi (primo,secondo,terzo)
 +  * se primo < secondo
 +    * allora: Se primo < terzo
 +      * allora il minimo è primo
 +      * altrimenti il minimo è terzo
 +    * altrimenti: Se secondo < terzo
 +      * allora il minimo è secondo
 +      * altrimenti il minimo è terzo
 +  * visualizzare minimo
 +
 +^ var. di input ^ tipo ^ var. di output ^ tipo ^ var. di lavoro ^ tipo ^
 +| primo | num. intero | - | - | - | - |
 +| secondo | num. intero | - | - | - | - |
 +| terzo | num. intero | - | - | - | - |
 +| - | - | minimo | num. intero |   | - |
 +
 +>> **Suggerimento** per la traduzione del codice: quando si legge il diagramma di flusso, seguire e tradurre per primo il percorso sempre "vero" e per ultimo il percorso sempre "falso".
 +
 +<file python 33a.py>
 +# versione senza elif
 +primo = int(raw_input("Inserire tre numeri interi separandoli con 'invio' \n"))
 +secondo = int(raw_input())
 +terzo = int(raw_input())
 +if primo < secondo :
 +    if primo < terzo :
 +        minimo = primo
 +    else:
 +        minimo = terzo
 +else:
 +    if secondo < terzo :
 +        minimo = secondo  
 +    else:
 +        minimo = terzo
 +print minimo
 +</file>
 +
 +Nella soluzione appena vista è facile capire, per ogni else, a quale if si riferisce, grazie all'indentazione.
 +
 +<file python 33b.py>
 +# versione con elif
 +primo = int(raw_input("Inserire tre numeri interi separandoli con 'invio' \n"))
 +secondo = int(raw_input())
 +terzo = int(raw_input())
 +if primo < secondo :
 +    if primo < terzo :
 +        minimo = primo
 +    else:
 +        minimo = terzo
 +elif secondo < terzo :
 +    minimo = secondo  
 +else:                # a quale if fa riferimento questo else?
 +    minimo = terzo
 +print minimo
 +</file>
 +
 +In quest'ultima soluzione non è facile capire a quale if fa riferimento l'ultimo else. Questa è un'ambiguita del linguaggio che si può risolvere stabilendo una regola: ogni else si riferisce all'if più vicino (in questo caso all'elif piu' vicino).
 +
 +=== Condizione con operatore logico AND ===
 +
 +<file python 34.py>
 +# Questo programma è stato scritto da Fabio
 +# visualizza il minimo di tre numeri
 +# utilizzando gli operatori logici in alternativa alle condizioni annidate
 +primo = int(raw_input("Inserire tre numeri interi separandoli con 'invio' \n"))
 +secondo = int(raw_input())
 +terzo = int(raw_input())
 +if primo < secondo and primo < terzo :
 +    minimo = primo
 +elif secondo < terzo :
 +    minimo = secondo
 +else:
 +    minimo = terzo
 +</file>
 +
 +
 +Esercizi:
 +
 +    - esercizio: chiedere due numeri e visualizzarli in ordine inverso
 +    - esercizio: chiedere due numeri, senza un ordine, visualizzare uno dei tre messaggi: sono ordinati, sono disordinati, sono uguali.
 +    - esercizio: un utente conosce sia la temperatura esterna che l'umidità relativa e fornisce questi due dati ad un programma. Il programma deve visualizzare:
 +      - "ghiaccio" se la temperatura è minore di zero
 +      - "no ghiaccio" in caso contrario.
 +      - inoltre nel primo caso deve visualizzare:
 +        - "neve" se l'umidità è maggiore di 90%
 +        - "no nece" in caso contrario
 +      - nel secondo caso deve visualizzare:
 +        - "probabile" pioggia se l'umidità è maggiore di 95%
 +        - "no pioggia" in caso contrario
 +
 +
 +=====Struttura iterativa=====
 +
 +La struttura iterativa può essere studiata come composta da diversi elementi (che possono anche coincidere tra loro):
 +  - un'eventuale variabile //contatore// (per numerare e contare quante sono le ripetizioni effettuate)
 +  - un'eventuale variabile //totalizzatore// (per accumulare l'eventuale risultato di tutte le operazioni ripetute)
 +  - la valutazione di un'espressione logica di uscita o //condizione di uscita// (per terminare in qualche modo la ripetizione)
 +  - un'eventuale istruzione che modifica la variabile contenuta nella condizione di uscita (ad esempio l'incremento del contatore...)
 +A seconda della posizione occupata dalla condizione di uscita all'interno della ripetizione, la struttura iterativa può essere di due tipi:
 +  * precondizionale
 +  * postcondizionale
 +In pratica, nel tipo //precondizionale//, quando la condizione di uscita //non// è verificata, la ripetizione non viene mai eseguita, mentre nella //postcondizionale// la ripetizione viene eseguita sempre almeno una volta. In entrambi i casi si esce dal ciclo di ripetizione quando la condizione diventa falsa.
 +
 +
 +==== Struttura iterativa postcondizionale ====
 +
 +Anche se in teoria esiste, si possono scrivere programmi senza usarla, quindi per ora viene omessa...
 +
 +
 +==== Struttura iterativa precondizionale====
 +
 +//Precondizionale// significa che la //condizione di uscita// precede la ripetizione, quindi, in questo caso, potrebbe accadere che, se la condizione non è verificata, la ripetizione non sia mai eseguita
 +
 +>> La struttura iterativa //precondizionale// in Python si può realizzare in due modi: per tradurre un diagramma di flusso si presta molto bene la struttura //while//, mentre si può usare //for// nel caso in cui la ripetizione riguardi una sequenza predefinita (come una sequenza di passi numerati o come una lista ordinata di elementi).
 +
 +  * //while … ://
 +    * La condizione di uscita del rombo deve essere indicata dentro while. L'eventuale inizializzazione del contatore va indicata subito prima di while. Le istruzioni da ripetere, così come l'istruzione che modifica il valore del contatore, vanno indicate subito dopo while, indentate.
 +    * <code># eventuale inizializzazione contatore...
 +while … :
 +   …
 +</code>  
 +  * //for … in … ://
 +    * L'istruzione for si può capire facilmente con un esempio: 
 +      * <code>for i in range(5,1,-1) :
 +        print i</code>
 +      * che produce il seguente output <code>
 +5
 +4
 +3
 +2
 +</code>
 +
 +Il seguente esempio è stato tradotto in due diversi programmi, tra loro equivalenti, per capire come si usa while() e come si usa for(;;). Il programmatore è libero di scegliere le due forme perché sono equivalenti.{{ :appunti3s:cppiterazione.png?150|}}
 +  * //Esempio che visualizza la tabellina del numero inserito//
 +  * ripetere la seguente operazione per un indice (i) che va da 1 a 10
 +    * visualizzare in output il risultato dell'espressione: numero*i
 +
 +^ var. di input ^ tipo ^ var. di output ^ tipo ^ var. di lavoro ^ tipo ^
 +| numero | num. intero | - | - | i | num. intero |
 +
 +<file python 35a.py>
 +numero = int(raw_input("Inserisci un numero intero da 1 a 10"))
 +i=1;             # inizializzazione del contatore
 +while i <= 10 :  # condizione di uscita
 +    print numero * i,  # la virgola in fondo evita di andare a capo
 +    i = i + 1        # incremento contatore
 +</file>
 +
 +<file python 35b.py>
 +numero = int(raw_input("Inserisci un numero intero da 1 a 10"))
 +for i in range(1, 11, 1) # inizializzazione, condizione ed incremento...
 +    print numero * i,  # la virgola in fondo evita di andare a capo
 +</file>
 +
 +  * Esempio: Scrivere un programma che chieda cinque numeri e ne visualizzi la somma {{ :appunti3s:cppiterazione2.png?150|}}
 +  * inizializzare totale a zero
 +  * ripetere la seguente operazione per i che va da 1 a 5
 +    * chiedere in input numero
 +    * incrementare totale con numero
 +  * visualizzare totale
 +
 +Anche questo esempio viene risolto sia usando //while// che //for//
 +<file python 36a.py>
 +i = 1                    # inizializzazione del contatore
 +totale = 0               # inizializzazione del totalizzatore
 +while i <= 5 :
 +    numero = int(raw_input("Inserisci un numero intero"))
 +    totale = totale + numero
 +    i = i + 1
 +print totale
 +</file>
 +<file python 36b.py>
 +totale = 0               # inizializzazione del totalizzatore
 +for i in range(0, 5, 1) :
 +    numero = int(raw_input("Inserisci un numero intero"))
 +    totale = totale + numero
 +print totale
 +</file>
 +
 +==== Struttura iterativa annidata====
 + 
 +Scrivere un programma che visualizzi tutte le tabelline pitagoriche dall'uno al dieci. 
 +{{ :appunti3s:cppiterazionebis.png?150|}}
 +<file python 37.py> 
 +for i in range(1, 11, 1) : # inizializzazione, condizione ed incremento...
 +    for j in range(1, 11, 1) :
 +        print j * i,  # la virgola in fondo evita di andare a capo
 +    print             # alcune volte si deve andare a capo
 +</file>
 +
 +per allineare bene i numeri si deve sostituire la riga "print j * i" con la seguente
 +<code>        print '{0:3d}'.format(j * i)</code>
 +il codice nelle parentesi graffe ha il seguente significato: (vedere [[http://docs.python.org/library/string.html#formatstrings|documentazione string]])
 +  * 0: stampa il primo argomento, ma in questo caso non ci sono altri argomenti...
 +  * 3: larghezza minima di 3 caratteri
 +  * d: stampa come numero intero
 +
 +==== Struttura iterativa all'interno di struttura condizionale====
 +
 +  * Esempio in cui si inseriscono due numeri interi: se viene inserito prima un numero più piccolo e dopo un numero più grande, si devono visualizzare tutti i numeri intermedi, mentre in caso contrario si deve visualizzare solo il numero più piccolo.{{ :appunti3s:provaacontare.png?200|}}
 +  * Ad esempio, inserendo 5 e 9 viene visualizzato 6,7,8, mentre inserendo 9 e 5 viene visualizzato solo 5.
 +<file python provaacontare.py>
 +num1 = int(raw_input("Per favore inserire due numeri interi \n"))
 +num2 = int(raw_input())
 +if num1 < num2 :
 +    for i in range(num1+1,num2,1) :
 +        print i, 
 +else :
 +    print num2
 +</file>
 +
 +==== Struttura condizionale all'interno di struttura iterativa====
 +
 +  * Esempio in cui si inseriscono due numeri interi e si visualizzano tutti i numeri intermedi ad eccezione del numero 7. (inserendo 3 e 8 si visualizza: 3,4,5,6,8)
 +  * SENZA SOLUZIONE
 +
 +==== Numero di ripetizioni sconosciuto ====
 +
 +Eseguire la somma di tutti i numeri inseriti fino a che si inserisce 0 per visualizzare il totale. Non si conosce quanti numeri saranno inseriti, meglio usare //while//... {{ :appunti3s:cppiterazione3.png?150|}}
 +
 +<file python 38.py>
 +totale, numero = 0, -1       # inizializzazioni
 +while numero != 0 :
 +    numero = int(raw_input("inserire un numero (stop con zero)"))
 +    totale = totale + numero
 +print totale
 +}
 +</file>
 +
 +====== Cenni alla ricorsione ======
 +
 +Prerequisito a questo argomento: le funzioni.
 +
 +===== Premessa =====
 +
 +Un programma che ripete più volte la stessa operazione, __in teoria__, può essere scritto secondo due approcci:
 +  * l'iterazione (precedentemente vista)
 +  * la ricorsione
 +===== Esempio del fattoriale di un intero N =====
 +Chi volesse utilizzare l'approccio della iterazione per spiegare come si calcola il fattoriale, potrebbe usare le seguenti parole: 
 +  * ripetere per //i// da 1 a N
 +    * moltiplicare tra loro tutte i valori di //i//
 +Chi volesse utilizzare l'approccio della ricorsione, invece, potrebbe dire:
 +  * moltiplicare N * (N-1)
 +    * moltiplicare il risultato precedente per (N-2)
 +      * moltiplicare il risultato precedente per (N-3)
 +        * ... e così via... 
 +          * fino a 1
 +Nell'approccio ricorsivo, le parole "//e così via//" descrivono l'espressione della soluzione in termini di uso quotidiano. Quindi, sebbene, in teoria, ogni problema possa essere risolto usando entrambi gli approcci, vi sono alcuni problemi che si prestano ad essere risolti più facilmente in un modo piuttosto che nell'altro.
 +===== Condizioni =====
 +Per risolvere un problema con una ricorsione è necessario:
 +   * esprimere la soluzione del passo generico //i// nei termini del passo precedente (//i-1//), ad esempio: <code> fattoriale(i) = i*fattoriale(i-1); // esprime il problema nei termini di se stesso</code> 
 +   * esprimere una condizione di terminazione, ad esempio: <code>fattoriale(0) = 1;</code>
 +
 +MANCA ESEMPIO FATTORIALE
 +
 +===== Verifica =====
 +
 +L'utente inserisce un numero intero compreso tra 1 e 10. L'elaboratore visualizza tutti i numeri compresi tra 1 e 10 ad eccezione di quello inserito dall'utente. 
 +Se l'utente inserisce 4, il computer visualizza 1,2,3,5,6,7,8,9,10