Programmazione Valerio Perticone, Sergio Perticone Programmazione • La programmazione è un processo che parte dall'analisi di un problema computazionale ed arriva, mediante un'opportuna codifica formale, alla creazione di un programma (software) • Ma che significa computazionale? Computazione • Analizziamo una comune definizione matematica: • Radice quadrata di x • La radice quadrata di x è quel numero y che moltiplicato per sé stesso è uguale ad x • Questa definizione è esauriente per comprendere il significato di radice quadrata • Ma non fornisce informazioni su come calcolarla! Conoscenza • La definizione precedenza è un esempio di conoscenza proposizionale • A noi interessa conoscere un algoritmo che ci permetta in pratica di risolvere il nostro problema (calcolare la radice quadrata) • Erone di Alessandria (I secolo d.C.) ha descritto una procedura per calcolarlo, che costituisce uno di primi esempi di algoritmo (conoscenza procedurale) Algoritmo di Erone • Passo 1: Fissa una soglia t ad un valore arbitrariamente basso • Passo 2: Scegli un valore arbitrario y • Passo 3: Poni d uguale alla differenza in valore assoluto tra y² ex • Passo 4: Se tale d è inferiore a t, allora y è la soluzione quindi termina • Passo 5: Altrimenti, sostituisci y con la media tra y e x/y • Passo 6: Vai al punto 3 Domanda • Quello descritto è un programma? • No, benché sia una procedura, non c’è alcuna forma di codifica formale dell’algoritmo Codifica • Il concetto di codifica è strettamente collegato ai protocolli di comunicazione • Quando comunichiamo seguiamo istintivamente alcune regole implicite che sono note nella società in cui ci troviamo (una forma di “galateo”) • Esempio: la stretta di mano è un gesto comunemente associato al saluto (ma assume significato di lealtà sportiva in seguito ad una partita) Codifica • Con l’evoluzione della scrittura e del linguaggio, oggi associamo particolari segni o suoni a significati che sono molto lontani dall’oggetto • Esempio: SOS nel codice Morse Codifica • Nel linguaggio matematico il concetto di codifica è più rigoroso e richiede che non siano presenti ambiguità • La definizione formale di codifica si associa al concetto matematico di funzione • In particolare sono richieste funzioni iniettive Linguaggi di programmazione • Un linguaggio di programmazione è un linguaggio utilizzato per il controllo di una macchina • Il programmatore codifica le istruzioni da compiere utilizzando il linguaggio della macchina • Una macchina può essere un computer, uno smartphone, una lavatrice, … Un po’ di storia • • Prima dell’invenzione del computer sono stati definiti linguaggi di programmazione arcaici per esprimere in maniera rigorosa il processo di calcolo • Characteristica universalis (Gottfried Leibniz, 1666) • Macchina analitica di Babbage (Ada Lovelace, 1843) • Lambda calcolo (Alonzo Church, 1936) • Macchina di Turing (Alan Turing, 1936) Sono tutti precedenti all’invenzione del computer! Linguaggi di programmazione • Oggi esistono numerosi linguaggi di programmazione, dotati di alcune peculiarità e specializzazioni nell’ambito di applicazione • Esempi: • Java • MATLAB • R • Python Caratteristiche comuni • Istruzioni • Variabili • Operatori aritmetici e logici • Strutture per il controllo del flusso • Procedure Istruzioni • Un programma è descritto da un codice sorgente (o semplicemente sorgente). Il sorgente è composto da un numero finito di istruzioni disposte su righe separate istruzione 1 istruzione 2 // commento ... istruzione n • Il flusso del programma è dato dalla sequenza di istruzioni eseguite • Se non specificato diversamente, l’esecuzione avviene nell’ordine in cui compaiono le istruzioni • È possibile aggiungere commenti per specificare il significato delle istruzioni. I commenti non sono interpretati dalla macchina. Variabili • Le variabili possono essere considerate come scatole etichettate il cui contenuto può essere modificato o osservato quando necessario • Regole: • ogni variabile va dichiarata prima di essere utilizzata • ogni variabile ha un nome univoco • ogni variabile ha associato un tipo Pseudocodice • Per presentare algoritmi spesso si utilizza lo pseudocodice • Corrisponde ad un linguaggio di programmazione inventato e non veramente implementato, ma sufficientemente formale • In questo caso s’ignorano, ove possibile, tipi e dichiarazioni di variabili Assegnamento • Per assegnare un valore ad una variabile di nome x, useremo l’operatore di assegnamento = x = 42 x = 10 y = 4 // la variabile x adesso conterrà il valore intero 42 // adesso x contiene 10 // la variabile y contiene 4 Operatori aritmetici • • Possiamo manipolare le variabili numeriche utilizzando le comuni operazioni aritmetiche: • + (addizione) • - (sottrazione) • * (prodotto) • / (divisione) Tali operatori possono essere combinati in maniera non binaria: area = base * altezza perimetro = base*2 + altezza*2 // esempio binario Operatori unari • Esistono operatori unari, ovvero che operano su un solo operando • - (segno meno) • ++ (incremento) • -- (decremento) x = 3 x++ x-x = x + 1 // x è uguale a 4 // x è uguale a 3 // è equivalente a x++ y = 5 z = -y w = -z // z è uguale a -5 // w è uguale a 5 Operatori logici • Gli operatori logici valutano un predicato e producono una costante logica booleana che corrisponde al suo valore di verità (Vero o Falso) • Sono comunemente indicati con true o false • Un tipo di predicato sono, ad esempio, le relazioni d’ordine: • < (strettamente minore) • <= (minore o uguale) • > (strettamente maggiore) • >= (maggiore o uguale) Operatori logici • Esempi: p = 42 > 1 q = 21 < 21 m = 21 <= 21 // p sarà uguale a true // q sarà uguale a false // m sarà uguale a true • Esistono inoltre gli operatori di eguaglianza: • == (uguale) • <> (non uguale) • Esempi: p q m n = = = = (10 == 10) (12 <> 10) (12 <> 12) (p == q) // // // // p q m n sarà sarà sarà sarà uguale uguale uguale uguale a a a a true true false true Operatori logici • Gli operatori di confronto sono binari e ammettono solamente operandi che possono essere messi in relazione tra loro p = (10 == 10 == 11) q = (23 <= true) // errore // errore Connettivi logici • Oltre alle operazioni di eguaglianza, è possibile effettuare altre operazioni con i valori di verità • Le seguenti operazioni sono detti connettivi logici: • && (congiunzione logica: and) • || (disgiunzione logica: or) • ! (negazione logica: not) Tabella di verità Congiunzione logica (AND) && Disgiunzione logica (OR) || FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE TRUE TRUE TRUE FALSE FALSE TRUE FALSE TRUE TRUE TRUE TRUE TRUE TRUE TRUE Connettivi logici • Esempi: x p q m n = = = = = 5 (10 < x) || (2 < x) (x > 1) && (x == 3) !(x == 5) true || false // // // // p p m n sarà sarà sarà sarà uguale uguale uguale uguale a a a a true false false true Precedenza degli operatori • • Come per la matematica, esistono regole per determinare la precedenza degli operatori. Vale la seguente scala di priorità (in ordine di precedenza): • * / • + - • == <> < <= > >= • && • || Gli operatori binari allo stesso livello seguono la regola associativa da sinistra verso destra. Nel dubbio si utilizzano le parentesi. a = x / y * z b = x / (y * z) // a e b sono diversi! Variabili non scalari • Quando trattiamo quantità numeriche abbiamo a che fare con variabili scalari • In programmazione sono spesso necessarie grandezze non scalari, ovvero non direttamente rappresentabili tramite un numero • Un esempio classico è il vettore (o array) • L’array è un esempio di struttura dati Array • L’array è una sorta di contenitore dotato di un numero finito di cellette ordinate • Per accedere ad una cella (slot) si utilizza un indice numerico intero • Gli indici partono solitamente da 0 (ovvero la prima cella dell’array è indicata dal numero 0) Array v = [2, 4, 6, 8] x = v[0] y = v[3] z = v[4] v[2] = 0 // // // // // inizializzo con i valori tra parentesi quadre x conterrà 2 y conterrà 8 errore: indice fuori dai limiti l'array adesso sarà: [2, 4, 0, 8] 2 4 0 8 Record • Un altro tipo di variabile non scalare è il record • Un record può contenere valori relativi ad un’entità • Un record è composto da campi (fields) • Si accede ai vari campi utilizzando la notazione punto (variabile.campo) Record • Supponiamo di voler creare un record che rappresenta una persona fisica • Questo record conterrà i campi “nome” ed “età” p = {nome: "Mario", età: 35} x = p.età n = p.nome p.età++ p.nome = "Luigi" // // // // // salva in p i dati relativi a Mario salva in x l'età (35) salva in n il nome ("Mario") p è {nome: "Mario", età: 36} Mario è diventato Luigi Controllo del flusso • Nella forma più semplice, il flusso di un programma segue le istruzioni riga per riga • Spesso è necessario modificare l’ordine di esecuzione delle istruzioni nel caso di algoritmi più elaborati • Esistono diversi costrutti per il controllo del flusso, ma quelli fondamentali sono di due tipi: • alternativa • iterazione Alternativa • Usando il costrutto alternativa possiamo eseguire blocchi di codice in base al verificarsi di una condizione logica // semplice if (predicato) { blocco di istruzioni } // alternativa con else if (predicato) { blocco se predicato vero } else { blocco se predicato falso } • Ne esistono due tipi: • Nello pseudocodice le graffe delimitano le istruzioni appartenenti al blocco Alternativa • Esempi if x == 42 { y = 2 } else { y = 10 } // questa istruzione verrà eseguita se x è 42 // altrimenti, il codice eseguito sarà questo if (x < 10) || (z == 2) { y = 2 z = 18 } Iterazione • Il costrutto iterazione permettere di ripetere più volte un certo blocco di codice fintantoché il predicato è vero • La ripetizione viene anche chiamata ciclo (o loop) while (predicato) { blocco } • Il predicato viene anche chiamato condizione: il suo valore di verità è controllato una volta sola precedentemente all’esecuzione della prima istruzione del blocco Iterazione v = [ 1, 2, 3, 4, 5, 6, 7, 8 ] n = 8 // lunghezza array i = 0 while i < n { v[i] = v[i] * 2 i++ } • Quale sarà il contenuto di v al termine del ciclo? Iterazione • Spesso nei programmi si utilizza, per questioni pratiche, un ciclo “infinito” • Basta utilizzare come predicato la costante true introdotta in precedenza while true { // ciclo infinito } • Per interrompere l’esecuzione del ciclo si utilizza l’istruzione break break • Supponiamo di dover scrivere un videogioco in cui è presente un numero finito di vite e il gioco termina una volta esaurite le vite • Lo pseudocodice avrà questa forma: numeroVite = 3 while true { // codice che gestisce il gioco if numeroVite == 0 { break } // codice che gestisce i controlli } // codice che mostra game over e termina la partita Procedure • Le procedure (o funzioni) permettono di richiamare blocchi di codice in determinati punti dello stesso programma o di programmi diversi • Molte procedure sono fornite dai creatori del linguaggio di programmazione o da altri sviluppatori sotto forma di librerie (raccolte di procedure) • Alcune procedure restituiscono un valore come risultato Esempi di procedure // assegna ad y il risultato della funzione sqrt applicata a 9 y = sqrt(9) // assegna ad un valore casuale compreso tra 1 e 10 x = random(1, 10) if y == 3 { print(x) } else { abort() } // stampa a schermo il valore di x // termina il programma in maniera anomala Procedure • La dichiarazione di una procedura è caratterizzata da una parola chiave che ne precede il nome, dal nome della procedura e dai parametri in ingresso della procedura, racchiusi tra parentesi tonde • Nello pseudocodice useremo la parola chiave func // dichiarazione: func somma3(a, b, c) { return a + b + c } // utilizzo: x = somma3(2, 4, 8) // x conterrà 14 Procedure func abs(a) { if a < 0 { return -a } return a } • Che funzione matematica calcola questa procedura? Algoritmo di Erone // definizione func sqrt(x) { t = 0.001 y = random(1, x) while true { d = abs(y*y - x) if d < t { return y } y = (y + x/y) / 2 } } // esempio d'uso y = sqrt(9) // media tra y e x/y