Lezione 4 • Introduzione agli algoritmi, funzionale alla programmazione relativamente a: – gestione dei dati da utilizzare – gestione della successione di operazioni da compiere 1 4.1. Algoritmi e programmi • Algoritmo = descrizione rigorosa di un metodo che consente di ottenere un risultato attraverso passi elementari • Esempio: gli algoritmi per eseguire le 4 operazioni che ci sono stati insegnati alle elementari – in un linguaggio adatto ai bambini • Per programmare un calcolatore è necessario un linguaggio di programmazione; vediamo come arrivare ad un programma. 2 Algoritmi e programmi • Per costruire un programma conviene procedere con metodo, – passando da un’analisi del problema da risolvere – all’algoritmo di soluzione rappresentato in un “linguaggio” adatto all’uomo ma non troppo lontano dai linguaggi di programmazione – e infine al programma scritto nel linguaggio di programmazione prescelto 3 Algoritmi e programmi • Perché orientati alla programmazione introdurremo la nozione di – contenitore di dati – come astrazione dalla nozione di zona della memoria utilizzata da un computer per i dati • Qui consideriamo gli algoritmi descritti mediante – diagrammi di flusso – strumento per descrivere una successione di operazioni adatto all’uomo e orientato alla traduzione in un linguaggio di programmazione 4 4.2. Processo di sviluppo di un algoritmo orientato alla programmazione • Descriveremo i passi da seguire nella costruzione di un algoritmo, intesa come passo preliminare alla costruzione di un corrispondente programma. • Il processo delineato è adatto alla programmazione in piccolo – programmazione in piccolo =costruzione di programmi di dimensioni trattabili da un singolo programmatore • La programmazione in grande richiede processi di sviluppo ingegnerizzati, che non tratteremo 5 I passi del processo di sviluppo • A) Diamo un nome al problema e partiamo dall’analisi del problema • B) Scriviamo la specifica funzionale • C) A partire da un’idea dell’algoritmo, introduciamo i contenitori di dati necessari e le relative operazioni elementari • D) A partire da un’idea dell’algoritmo, scriviamo un diagramma di flusso che indica in modo preciso e non ambiguo la successione di operazioni da eseguire 6 A) Problema e analisi del problema • L’analisi del problema è il primo passo; deve fornire – un nome e una breve descrizione di cosa si vuol fare; – un elenco di requisiti: richieste a cui deve soddisfare il programma 7 Esempio di analisi del problema • Problema RADICI – Descrizione: vogliamo trovare le soluzioni reali di un’equazione di secondo grado – Requisiti: l’equazione può non avere soluzioni, avere due soluzioni coincidenti o due soluzioni distinte; a seconda dei casi, si vuole il messaggio: • “nessuna radice x” • “radici coincidenti = r” – dove r è il valore reale delle radici • “due radici distinte r1, r2” – dove r1, r2 sono i valori reali delle due radici 8 B) Specifica funzionale • Una specifica funzionale indica – quali sono i dati iniziali, cioè quelli da elaborare • detti anche ingressi all’algoritmo – che risultato si vuole, in funzione degli ingressi 9 Esempio: specifica funzionale • RADICI: specifica funzionale • Argomenti o ingressi: – a,b,c : numeri reali, coefficienti dell’equazione da elaborare • Risultati o uscite: – “nessuna radice” – “x1=x2 = r” se l’equazione a.x2+b.x+c ha radici coincidenti = r – “x1 = r1, x2 = r2” se l’equazione a.x2+b.x+c ha radici coincidenti = r1,r2 10 C) I contenitori di dati • Un algoritmo ha bisogno di tener traccia di ingressi e risultati: – sia il risultato finale – sia i risultati intermedi • Allo scopo, usa dei contenitori di dati • Un contenitore dati, detto anche variabile di programma, è un’astrazione della nozione di area di memoria contenente dei dati • I dati contenuti hanno un tipo, che caratterizza un insieme di elementi le operazioni possibili su di essi 11 I contenitori di dati • I contenitori di dati utilizzati per i risultati intermedi dipendono dall’algoritmo – quindi, a meno di casi assai elementari, è necessario avere già un’idea dell’algoritmo per determinarli – difficilmente sono TUTTI prevedibili sin dall’inizio; man mano che l’algoritmo prende forma, si possono aggiungere al volo nuovi contenitori 12 Il tipo di dati di un contenitore • TIPO DATI = insieme di elementi rappresentabili finitamente, dotato di operazioni primitive che si suppongono calcolabili dall’esecutore dell’algoritmo • ESEMPIO: il tipo degli interi – è l’insieme degli interi • essi sono rappresentabili da successioni finite di cifre con eventuale segno – dotato delle seguenti operazioni primitive (e calcolabili) • +, -, *, divisione intera, resto 13 Rappresentazione grafica dei contenitori di dati pippo: intero Nome contenitore e tipo 54 Contenuto = dato appartenete al tipo di dati associato al nome 14 I contenitori utilizzati da RADICI • Di quali contenitori abbiamo bisogno per RADICI? – Sicuramente di quelli per contenere i dati di ingresso ed il risultato • 3 contenitori per a,b,c ( ingressi ) – Eventuali contenitori per i risultati intermedi ed eventualmente quello finale 15 • Relativamente agli ingressi, abbiamo i contenitori: a : float a b : float b c : float c In blu indichiamo il nome del contenitore, in rosso il numero contenuto in esso Il tipo float corrisponde ai numeri rappresentati in floating point; le operazioni che assumiamo disponibili per esso sono le solite: somma, prodotto, radice, …. 16 D) L’algoritmo: primo passo • Descrivere brevemente l’idea dell’algoritmo – cioè i passi da eseguire per giungere alla soluzione usando i contenitori di dati e le operazioni disponibili su di essi in base al tipo di dati, a grandi linee • Puo’ darsi che una prima idea sia già stata raggiunta per trovare i contenitori dati più appropriati – in tal caso si procede ad un eventuale raffinamento dell’idea 17 L’idea dell’algoritmo di soluzione di RADICI • Risolvo il problema calcolando il discriminante delta dell’equazione, usando le operazioni di prodotto e differenza disponibili nel tipo float; • analizzo poi i vari casi di delta: – <0 – =0 – >0 • e caso per caso costruisco il messaggio da inviare in uscita. • Il dettaglio si ottiene con un diagramma di flusso: 18 L’idea dell’algoritmo di soluzione di RADICI • Si passa infine a dettagliare l’idea mediante un diagramma di flusso, che rende precise le regole da seguire per svolgere la corretta sequenza di passi di calcolo. • Nel nostro esempio il diagramma di flusso è il seguente – la successione di diapositive mostra anche come la successione dei vari passi determinata dal diagramma per i dati di ingresso 1,2,1. 19 Ingresso: 1, 2, 1 a:float Assegna ad a,b,c i valori d’ingresso Metti il valore di b2-4ac delta<0 c:float delta:float in delta falso vero vero MESSAGGIO: ‘nessuna soluzione’ b:float delta=0 MESSAGGIO: ‘radici coincidenti=’ -b/2a 20 falso MESSAGGIO: ‘radici distinte=’ (-b-radice(delta))/2a (-b+radice(delta))/2a Assegna ad a,b,c i valori d’ingresso Metti il valore di b2-4ac delta<0 b:float 1 2 c:float 1 delta:float in delta falso vero vero MESSAGGIO: ‘nessuna soluzione’ a:float delta=0 MESSAGGIO: ‘radici coincidenti=’ -b/2a 21 falso MESSAGGIO: ‘radici distinte=’ (-b-radice(delta))/2a (-b+radice(delta))/2a Assegna ad a,b,c i valori d’ingresso Metti il valore di b2-4ac delta<0 b:float 1 2 c:float 1 delta:float in delta 0 falso vero vero MESSAGGIO: ‘nessuna soluzione’ a:float delta=0 MESSAGGIO: ‘radici coincidenti=’ -b/2a 22 falso MESSAGGIO: ‘radici distinte=’ (-b-radice(delta))/2a (-b+radice(delta))/2a Assegna ad a,b,c i valori d’ingresso Metti il valore di b2-4ac delta<0 b:float 1 2 c:float 1 delta:float in delta 0 falso vero vero MESSAGGIO: ‘nessuna soluzione’ a:float delta=0 MESSAGGIO: ‘radici coincidenti=’ -b/2a 23 falso MESSAGGIO: ‘radici distinte=’ (-b-radice(delta))/2a (-b+radice(delta))/2a Assegna ad a,b,c i valori d’ingresso Metti il valore di b2-4ac delta<0 b:float 1 2 c:float 1 delta:float in delta 0 falso vero vero MESSAGGIO: ‘nessuna soluzione’ a:float delta=0 MESSAGGIO: ‘radici coincidenti=’ -b/2a 24 falso MESSAGGIO: ‘radici distinte=’ (-b-radice(delta))/2a (-b+radice(delta))/2a Assegna ad a,b,c i valori d’ingresso Metti il valore di b2-4ac delta<0 b:float 1 2 c:float 1 delta:float in delta 0 MESSAGGIO: radici coincidenti = -1 falso vero vero MESSAGGIO: ‘nessuna soluzione’ a:float delta=0 MESSAGGIO: ‘radici coincidenti=’ -b/2a 25 falso MESSAGGIO: ‘radici distinte=’ (-b-radice(delta))/2a (-b+radice(delta))/2a Sui diagrammi di flusso • L’esecutore di un algoritmo, sia esso il computer o un umano, compie; sono di due fondamentali: – calcoli primitivi: ottenibili mediante le operazioni primitive dei tipi di dati (sostanzialmente, valutando espressioni) – azioni: consistono nel modificare il contenuto dei contenitori di memoria, eventualmente eseguendo calcoli primitivi 26 Calcoli primitivi • Valutazione di espressioni in cui compaiono i nomi dei contenitori di dati utilizzati e solo operazioni primitive disponibili sui relativi tipi di dati; • il valore dell’espressione è riferito allo – STATO di memoria dell’algoritmo = contenuto attuale dei suoi contenitori dati 27 Calcoli primitivi Nello stato di memoria: a : float 2 b : float 4 Val(b . b - 4 . a . c) = c : float 2 0 b . b - 4 . a . c è un’espressione valutabile perché contiene operazioni primitive disponibili nel tipo float 28 Calcoli primitivi: espressioni booleane • Fra le espressioni valutabili assumono particolare importanza quelle di tipo booleano • il tipo booleano contiene due valori – vero, falso • Esempi di espressioni booleane disponibile nei tipi numerici è • x<y • (x + 5) = y • ecc. 29 Azioni • Modificano lo stato di memoria, cioè i valori dei contenitori dati • Le azioni più semplici sono gli assegnamenti, della forma: – metti ESPRESSIONE in CONTENITORE – l’esecutore valuta l’ESPRESSIONE e mette il valore così calcolato in CONTENITORE, sostituendone il valore precedente • Esempio di altre azioni: leggi da ingresso, scrivi in uscita 30 Esempio di assegnamento a : float 2 b : float 4 c : float 2 delta : float 7 metti b . b - 4 . a . c in delta a : float 2 b : float 4 c : float 2 31 delta : float 0 Possiamo ora rivedere i diagrammi di flusso metti x+y in y ; metti x-1 in x; falso vero x=0 Blocchi decisionali Blocchi di elaborazione; contengono una condizione booleana contengono sequenze di azioni se vera, si segue la freccia vero, se falsa la freccia falso 32 Strutture di controllo modulari • Un diagramma di flusso si ottiene collegando le frecce uscenti dai blocchi di elaborazione e decisionali • Una buona norma è attenersi a diagrammi con strutture predefinite, con una sola freccia entrante ed una sola uscente; • tali strutture sono dette strutture di controllo e sono alla base della programmazione strutturata • ciò consente di modularizzare (cioè dividere in parti o moduli) il diagramma; è utile poiché spesso i moduli corrispondono a sottoproblemi 33 Strutture di controllo principali vero sequenza selezione 34 falso Strutture di controllo principali falso iterazione vero 35 Esempio di decomposizione modulare 36