Informatica Generale a.a. 2006/2007 Demis Ballis <[email protected]> Dipartimento di Matematica e Informatica Università degli Studi di Udine Obiettivi • conoscere il calcolatore (parte HWe SW) • apprendere le basi della programmazione (imparare a formalizzare e risolvere problemi con l’ausilio del calcolatore) Programma del corso • PARTE 1 (Algoritmi) Il trattamento automatico dell’informazione. Il modello di Von Neumann. Formalizzare l’informazione: problemi e algoritmi. Rappresentazione degli algoritmi mediante diagrammi di flusso, pseudocodice e codice Java. Elementi base sui linguaggi di programmazione. La codifica dell’informazione: rappresentazione dei dati testuali e codifica dei dati numerici. Programma del corso • PARTE 2 (Architetture) Elementi di architettura degli elaboratori. Il modello di funzionamento della CPU. Memoria: organizzazione e funzionamento. Dispositivi di I/O. Elementi di sistemi operativi. Struttura e funzionalità di un sistema operativo. Gestione dei processi, della memoria e dei dispositivi di I/O. Il file system. Applicazioni utente. Reti di calcolatori e internet: LAN e WAN. World Wide Web, browser e protocollo http (cenni). Il linguaggio HTML per la creazione di ipertesti. Programma del corso • PARTE 3 (Programmazione ad oggetti) Elementi base della programmazione ad oggetti. Classi, istanze e messaggi. Principali caratteristiche del paradigma di programmazione ad oggetti: ereditarietà, incapsulamento e polimorfismo. Un linguaggio orientato agli oggetti: Java (cenni). (Sarà il linguaggio che useremo nel corso di laboratorio) Altre informazioni • Testo consigliato: D. Sciuto, G. Buonanno, W. Fornaciari e L. Mari. Introduzione ai sistemi informatici. McGraw-Hill, seconda edizione, 2002. • Trasparenze e dispense del docente • Reperibili sul sito Web http://www.dimi.uniud.it/~demis Altre informazioni • Orario di ricevimento: Lunedì (dopo lezione). • Modalità d’esame: esame scritto + eventuale orale. Un po’ di storia... Sumeri e Babilonesi Abitanti delle prime civiltà di Sumeri tengono già traccia di operazioni commerciali utilizzando apposite tavolette. L'estratto conto è molto antico! Leonardo da Vinci (1452-1519) Disegni e progetti di calcolo ritrovati solamente nel 1967 e che dimostrano come egli, già attorno al 1500 (150 anni prima di Blaise Pascal!) avesse immaginato un sistema meccanico di calcolatrice basata su ruote dentate (lo scritto fa parte di quello che oggi viene chiamato "Codice di Madrid) perfettamente funzionante. Blaise Pascal (1623-1662) Filosofo, matematico e fisico francese. Blaise Pascal a venti anni realizza una celebre macchina per eseguire addizioni e sottrazioni automaticamente, la 'Pascalina'. Le addizioni venivano eseguite mediante la somma delle rotazioni degli ingranaggi e le sottrazioni come complemento al 10 (principio che fu utilizzato anche da molte calcolatrici meccaniche fino a pochi anni fa). Le moltiplicazioni erano delle addizioni ripetute. Lo scopo per cui progettò questa calcolatrice fu quello di aiutare il padre nel calcolo della riscossione delle tasse. Pensò che la macchina potesse essere utile anche ad altri, la fece brevettare e ne costruì anche un certo numero di esemplari (circa 50). Gottfried W. Leibniz (1646-1716) Oltre a una macchina calcolatrice automatica in grado di eseguire le quattro operazioni e l'estrazione di radici quadrate, lasciò alcune idee fondamentali per lo sviluppo della logica matematica e per il futuro funzionamento dei calcolatori digitali. Nel 1670, ignaro delle invenzioni di B.Pascal e di W.Schickard, il grande matematico e filosofo tedesco si immerse nella progettazione di una macchina che non fosse una semplice calcolatrice, ma che potesse eseguire qualsiasi processo di ragionamento. Più tardi, apprese dalla lettura dell'opera "Pensieri" dell'esistenza della pascaline, Leibniz concentrò il suo sforzo nella realizzazione di un congegno che potesse eseguire velocemente moltiplicazioni e divisioni, cosa che la macchina di Pascal non era in grado di eseguire. Nel 1674 Leibniz presentò a Londra il suo progetto, denominato Stepped Reckoner (calcolatrice a scatti). Il prototipo, però, aveva molte difficoltà a funzionare. Charles Babbage (1791-1871) Matematico inglese. A lui si deve la descrizione del primo calcolatore digitale automatico di uso generale, la cosiddetta 'macchina analitica', modello per tutti i successivi calcolatori digitali universali. Per questa macchina, precorrendo i tempi, aveva immaginato la possibilità di introdurre da un lato le regole (gli algoritmi) e dall'altro i valori (le variabili e le costanti). Il modo più semplice di fare questo consisteva nell' utilizzo di schede perforate o nastri perforati. La macchina doveva essere in grado di eseguire operazioni ricorrenti nel calcolo delle tavole e, per questo, dovevano esserci varie schede, una per ogni operazione da compiere, che venivano unite in un nastro nella opportuna sequenza. Altre schede perforate contenevano i dati. La macchina analitica era costituita da due parti: lo store (memoria) che immagazzinava i dati e i programmi e che nella quale erano conservati anche tutti i risultati intermedi dei calcoli. Il mill (unità di calcolo) che conteneva il programma vero e proprio. Babbage non vedrà mai funzionare la sua Macchina Analitica. Ada Lovelace (1815-1852) Il primo software mai scritto da un essere umano fu ideato da una mano femminile e fu una mente di donna a prefigurare alcune delle basi concettuali della programmazione: Ada Lovelace. Ada si appassiona all’opera di Babbage, di cui intuisce “l’universalità delle idee” e tra i due inizia un fitto scambio di lettere, piene di numeri, fatti e fantasie. Ada Byron descrive la Macchina di Babbage come uno strumento programmabile, in grado di agire in base a delle istruzioni generali. Con incredibile lungimiranza, ne prevede le applicazioni nel calcolo matematico, prefigura l’intelligenza artificiale e persino la computer music, affermando che la macchina sarà cruciale per il futuro della scienza. A titolo di esempio, spiega il modo in cui la macchina potrebbe effettuare un determinato calcolo, scrivendo quel che viene unanimemente riconosciuto come il primo software della storia. George Boole (1815-1864) Logico e matematico inglese. George Boole creò lo strumento concettuale che sta alla base del funzionamento del calcolatore e che, in suo onore, va sotto il nome di 'algebra booleana'. Si tratta di un calcolo logico a due valori di verità con alcune leggi particolari, che consente di operare su proposizioni allo stesso modo che su entità matematiche. La sua logica, oggi, sta alla base della struttura dei componenti elettronici denominati "porte logiche" ed è la base del funzionamento dei calcolatori elettronici. John Von Neumann (1903-1957) Nell'agosto 1944, von Neumann si buttò a capofitto nel progetto del calcolatore ENIAC. ENIAC permetteva la memorizzazione interna dei programmi. La programmazione, che fino ad allora richiedeva una manipolazione diretta ed esterna dei collegamenti, era così ridotta ad un'operazione dello stesso tipo dell'inserimento dei dati, e l'ENIAC diveniva la prima realizzazione di un computer programmabile nel senso moderno del termine. All'Istituto di Princeton si dedicò alla progettazione di un nuovo calcolatore, producendo una serie di lavori che portarono alla definizione di quella che oggi è nota come architettura von Neumann: in particolare, la distinzione tra memoria primaria (ROM) e secondaria (RAM), e lo stile di programmazione mediante diagrammi di flusso. Alan M. Turing (1912-1954) La macchina di Turing non è altro che (la semplificazione) dell'odierno computer. Turing descrisse una macchina che sarebbe stata capace di leggere una serie su una banda composta dalle cifre uno e zero. Questi uni e questi zeri descrivevano i passaggi che erano necessari per risolvere un particolare problema o per svolgere un certo compito. La macchina di Turing avrebbe letto ogni passaggio e l'avrebbe svolto in sequenza dando la risposta giusta. Questo concetto era rivoluzionario per quel tempo in quanto molti computer negli anni '50 erano progettati per un scopo preciso o per uno spettro limitato di scopi. Ciò che Turing intravvedeva era una macchina che riusciva a fare tutto, una cosa che oggigiorno diamo per scontata. Turing mise le sue capacità matematiche al servizio del Department of Communications inglese per decifrare i codici usati nelle comunicazioni tedesche (codice Enigma). Turing pensava che il si potesse riprodurre l’intelligenza umana nel calcolatore (TEST di TURING). L’informazione • Diverse proposte in letteratura • Bateson, “Ricevere informazioni vuol dire necessariamente ricevere notizie di differenza” (Es.: Luce accesa/spenta, 1/0,...) • Shannon, visione probabilistica. Un evento porta molta informazione se e’ poco probabile. (”Al polo nord fa freddo”). Problemi e soluzioni • Ogni problema necessita di informazione per essere risolto. • L’informazione deve essere elaborata al fine di ottenere una soluzione (Elaborazione dell’informazione). • Ogni problema è dunque caratterizzato da: • insieme di dati di partenza • un risultato cercato Problemi e soluzioni • Una soluzione può essere intesa come una procedura che genera un risultato a partire dai dati iniziali. • Creazione di una soluzione ed esecuzione di una soluzione sono generalmente competenze distinte che possono riguardare soggetti distinti Problemi e soluzioni • Supponiamo di avere due soggetti: il primo capace di formulare una soluzione (uomo), il secondo in grado di eseguire una soluzione (calcolatore) • analisi del problema e identificazione di una soluzione da parte del primo soggetto; • traduzione della soluzione da parte del primo soggetto in termini comprensibili al secondo (linguaggi di programmazione ad alto livello); • interpretazione e attuazione della soluzione da parte del secondo soggetto. Problemi e sottoproblemi • La descrizione di un problema può essere piuttosto complessa. Es.: Calcolo dell’area del cerchio A=!R2 • Soluzione scomporre il problema in sottoproblemi più semplici (approccio Topdown), Es. calcolo del qudrato del raggio al fine di calcolare l’area del cerchio. Problemi e sottoproblemi • Un problema si dice elementare se la sua soluzione corrisponde ad un’azione elementare che può essere compiuta direttamente dall’esecutore. • Una soluzione e’ effettiva per un esecutore se • l’esecutore e’ in grado di interpretare la soluzione ed associarvi le operazioni che devono essere compiute; • l’esecutore e’ in grado di compiere tali azioni in un tempo finito. Problemi e sottoproblemi • l’approccio top-down alla soluzione di un problema e’ il seguente • se la soluzione del problema è effettiva, allora l’esecutore la attua; • altrimenti il problema viene scomposto in sottoproblemi e per ognuno di questi si riapplica la metodologia di scomposizione top-down. Problemi e sottoproblemi • • • • • • In generale, un insieme di problemi è una procedura effettiva se tutti i problemi dell’insieme sono elementari è fissato l’ordine di soluzione dei problemi si specifica esplicitamente come un problema utilizza i risultati dei suoi sottoproblemi. Esempio: calcolo dell’area di una figura complessa. L’esecutore • • L’esecutore è caratterizzato da • il linguaggio che è in grado di interpretare, il quale deve essere formalmente specificato (caratterizzazione sintattica) • • l’insieme delle azioniche è in grado di compiere l’insieme di regole che associano ad ogni costrutto sintattico le opportune azioni da compiere (caratterizzazione semantica) Le soluzioni effettive caratterizzate formalmente si chiamano ALGORITMI! Algoritmi • Un algoritmo è dunque una sequenza finita di passi, scritta in un opportuno linguaggio interpretabile dall’esecutore, che permette di calcolare un risultato a partire da un insieme di dati in ingresso. • Un algoritmo permette di risolvere una classe di problemi omogenei. Proprietà degli algoritmi Un algoritmo deve essere • Finito • Non ambiguo • Effettivo Realizzazione di un programma Esigenze utente Analisi soluzione informale Formalizzazione algoritmo programmazione programma traduzione Debugging esecuzione Esempio di algoritmo Calcolo del massimo fra 2 numeri 1. Leggi un numero dall’esterno e mettilo nella variabile X. 2. Leggi un numero dall’esterno e mettilo nella variabile Y. 3. Calcola la differenza d fra x e y (d ! X-Y) 1. Se (d > 0) allora stampa “il massimo è X”, altrimenti stampa “il massimo è Y”. Altri esempi: • Determinare il maggiore fra tre numeri • Determinare il massimo fra n numeri naturali. Diagrammi di flusso • Un metodo per rappresentare graficamente gli algoritmi. Input/ Output predicato sotto programma Start Elaborazione Stop Esempio Start Leggi X Leggi Y d ! X-Y d>0? SI NO Stampa X Stampa Y Stop La programmazione strutturata Un algoritmo è strutturato in blocchi di istruzioni. • Vantaggio: codice. maggior leggibilità e pulizia del • Blocchi: sequenziali, condizionali, iterativi. • Le istruzioni di input/output e di assegnamento possono essere considerate come dei blocchi sequenziali atomici. Blocco sequenziale • E’ costituito da una sequenza di (sotto-)blocchi che saranno eseguiti sequenzialmente. { Blocco 11 Blocco Blocco Sequenziale Blocco 12 Blocco } Blocco 1 Blocco 2 . . . Blocco N Blocco 1N Blocco Blocco i, i=1,..N, può essere un blocco sequenziale, condizionale, iterativo Blocco condizionale • Il blocco condizionale permette di scegliere tra due azioni in base a una condizione logica. Blocco Condizionale Condizione SI Blocco 11 Blocco NO Blocco 12 Blocco Se <Condizione> allora Blocco 1 altrimenti Blocco 2 Blocco i, i=1,..2, può essere un blocco sequenziale, condizionale, iterativo Blocco condizionale (semplificato) • Tale blocco permette di decidere di eseguire un’azione in base a una condizione logica. Blocco Condizionale Semplificato Condizione Se <condizione> allora Blocco 1 SI Blocco 11 Blocco Blocco 1 può essere un blocco sequenziale, condizionale, iterativo Blocco iterativo (controllo in testa) • Il blocco iterativo con controllo in testa permette di ripetere un blocco di istruzioni finché la condizione logica rimane vera Blocco Iterativo (controllo in testa) Mentre <condizione> fai Blocco 1 Condizione SI NO Blocco 11 Blocco Blocco 1 può essere un blocco sequenziale, condizionale, iterativo Blocco iterativo (controllo in coda) • Permette di eseguire almeno una volta il blocco contenuto nel ciclo. Si ripete il blocco finché la condizione logica viene verificata. Blocco Iterativo (controllo in coda) Ripeti Blocco 1 finché <condizione> Blocco 11 Blocco NO Condizione SI Blocco 1 può essere un blocco sequenziale, condizionale, iterativo Diagramma di Flusso Start Leggi X,Y D!X-Y D>0? SI NO Scrivi Max è X Scrivi Max è Y Stop Max fra 3 numeri Input: tre numeri distinti Output: il massimo fra i tre numeri 1. Leggi X,Y,Z 2. Se (X>Y) allora 2.1. Se (X>Z) allora 2.1.1. Stampa altrimenti 2.1.2. Stampa altrimenti 2.2. Se (Y>Z) allora 2.2.1. Stampa altrimenti 2.2.2. Stampa “il max e’ X” “il max e’ Z” “il max e’ Y” “il max e’ Z” Diagramma di Flusso Start Leggi X,Y,Z SI NO X>Y? SI Scrivi max e' X X>Z? NO SI Scrivi max e' Z Scrivi max e' Y Stop NO Y>Z? Scrivi max e' Z Codifica dell’informazione • Gli algoritmi sono costituiti da istruzioni (blocchi sequenziali, condizionali, iterativi) che operano su dati. • Per trasformare un programma in una descrizione eseguibile da un calcolatore è necessario rappresentare istruzioni e dati in un formato memorizzabile e facilmente manipolabile. Codifica dell’informazione • Rappresenteremo l’informazione numerica e non numerica mediante sequenze di simboli scelti da un insieme chiamato alfabeto. • Ad ogni alfabeto è associato un insieme di regole di composizione che consentono di costruire le successioni di simboli. Successioni che sono costruite mediante le regole di composizione si dicono “ben formate”. Esempio Rappresentazione usuale dei numeri frazionari in base 10 Alfabeto={”0”,”1”,”2”,”3”,”4”,”5”,”6”,”7”,”8”,”9”, “,”} 103,56 successione ben formata 12,45,67 successione non ben formata Codifica dell’informazione • Oltre a dare delle regole di composizione per rappresentare l’informazione (parte sintattica), è necessario assegnare all’informazione un significato mediante dei codici (parte semantica). Esempio 2 1 0 -1 -2 103,56 significa 1*10 +0*10 +3*10 +5*10 +6*10 Codifica dell’informazione • Dato un alfabeto di n simboli, si possono generare nk successioni di k simboli. • Generalmente non tutte le successioni codificano dell’informazione (solo le successioni ben formate) Esempio 4 Con un alfabeto di 10 simboli si possono ottenere 10 =10.000 sequenze di lunghezza 4. Codifica binaria • • • • Un alfabeto piuttosto semplice e allo stesso tempo molto comodo è l’alfabeto binario, il quale è composto da soli due simboli. A2={0,1} I calcolatori utilizzano per la memorizzazione dell’informazione dei dispositivi bistabili (bit - Binary digIT), in grado di assumere due sole configurazioni. Nell’ipotesi che ogni successione di bit sia ben formata, utilizzando k l’alfabeto A2 e k bit si possono ottenere 2 successioni diverse. Codifica binaria • 8 bit = 1 Byte • 2 Byte = 1 KByte • 2 KByte = 2 Byte = 1 MByte • 2 MByte = 2 KByte = 2 Byte = 1 GByte 10 10 10 20 20 30 Dati non numerici • Dati non numerici esempi: caratteri alfanumerici (’a’,’b’,’=’,...), sequenze di caratteri (”pippo”, “mamma”, ...). • Problema: come codificare mediante un codice binario dei dati non numerici? Dati non numerici • Dato un insieme di dati non numerici S costituito da #S elementi, qual è il numero minimo di bit per codificare tutti gli elementi mediante una codifica binaria che sia univoca? • k Sappiamo che con k bit possiamo codificare n=2 elementi. Se n=#S allora k è uguale al tetto di log #S, dove il tetto di un numero p è 2 il minimo intero superiore a p. • Esempio: S= {Lun,Mar,Mer,Gio,Ven,Sab,Dom}, #S=7. Quindi log #S 2 tetto(log2 #S)=tetto(log2 7)= 3 Algoritmo per la codifica dei dati non numerici Problema: dato un insieme S di dati non numerici, determinare una codifica binaria univoca per gli elementi di S. Soluzione: Dato un insieme S da codificare, un singolo bit permette di distinguere i dati in due sottoinsiemi. Iterando tale procedimento sui sottoinsiemi identificati, siamo in grado di generare delle successioni di bit che identificano in maniera non ambigua i singoli elementi di S. Esempio S Lun Mar Mer Gio Lun Mar Mer Gio Ven Sab Dom Ven Sab Dom Lun Mar Mer Gio Ven Sab Dom Non usata! 000 001 010 011 100 101 110 111 0 1 Lun Mar 00 Mer Gio 01 Ven Sab 10 Dom 11 Dati non numerici • Volendo realizzare una codifica binaria per documenti scritti in linguaggio naturale bisogna prima stabilire il numero di simboli necessari. (Es. 26 lettere minuscole, 26 lettere maiuscole, segni di interpunzione, 10 cifre decimali,caratteri speciali...) • Sono circa 120 simboli, per la cui codifica sono necessari almeno 7 bit. Dati non numerici • Codifica ASCII (128 caratteri, 7 bit) • Codifica ASCII estesa (256 caratteri, 8 bit) • codifica UNICODE (65535 caratteri, 16 bit) • i primi 128 caratteri della codifica UNICODE corrispondono al codice ASCII • Anche UNICODE non è sufficiente :-( Istruzioni • I programmi sono codificati mediante un linguaggio di basso livello chiamato linguaggio macchina. • Anche le istruzioni del linguaggio macchina sono codificate mediante un codice binario. • • assegnare un codice univoco ad ogni singola istruzione (opcode) • il numero di operandi dipende dal tipo di istruzione. (ES: l’istruzione ADD (somma) ha due operandi, l’istruzione HALT ha 0 operandi). oltre all’opcode è necessario codificare gli eventuali riferimenti agli operandi necessari all’esecuzione dell’istruzione. Codifica dei dati numerici • Codifica dei numeri senza segno • • rappresentzione dei numeri senza segno in base B, B>1. conversioni di base: • • • • Da base 10 a base B, B>1 Da base B, B>1 a base 10 Da base B, B>1 a base B’, B’>1 Conversioni rapide: • • da base 8 a base 2 e viceversa da base 16 a base 2 e viceversa Notazione Una base B di dimensione n e’ un insieme di n cifre {0,1,... n-1} Esempi: {0,1} base 2 {0,1,2} base 3 {0,1,2,3,4,5,6,7} base 8 {0,1,2,3,4,5,6,7,8,9} base 10 {0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F} base 16 (cn-1 cn-2 ... cn-1 c1 c0)B !rappresenta un numero senza segno ! di n cifre in base B. Conversioni di base Problema: convertire un numero senza segno da base B a base 10. Soluzione: dato il numero senza segno in base B (cn-1 cn-2 ... cn-1 c1 c0)B il corrispondente valore in base 10 si calcola con la seguente formula: cn-1*2n-1 + cn-2*2n-2 + ... + c1*21 + c0*20 Esempio: (101011)2 corrisponde a (43)10, infatti 1*25+0*24+1*23+0*22+1*21+1*20 = 32+0+8+0+2+1 = 43 Conversioni di base Problema: convertire un numero senza segno da base 10 a base B. Soluzione: dato un numero senza segno X in base 10, si deve calcolare il corrispondente valore in base B (cn-1 cn-2 ... cn-1 c1 c0)B. Dividendo X per la base B, si ottiene come resto la cifra c0 e un certo quoziente Y1. Dividendo Y1 per la base B, si ottiene come resto la cifra c1 e un certo quoziente Y2. Iterando il procedimento fino a raggiungere il quoziente 0, si ottiene il numero in base B cercato. Conversioni di base Esempio: (12)10 corrisponde a (112)3, infatti 14:3=4 2 c0 4:3=1 1:3=0 1 1 c1 c2 Esempio: (12)10 corrisponde a (1100)2, infatti 12:2=6 0 c0 6:2=3 3:2=1 1:2=0 0 1 1 c1 c2 c3 Conversioni di base Problema: convertire un numero senza segno da base B1 a base B2. Soluzione: convertire prima il numero da base B1 a base 10 e in seguito convertire il valore risultante da base 10 a base B2. Esempio: (101011)2 corrisponde a (1121)3, infatti (101011)2 = (43)10 = (1121)3 Conversioni rapide In alcuni casi passare da una base B1 a una base B2 può essere molto semplice. È questo il caso delle conversioni da base 8 a base 2, da base 2 a base 8, da base 16 a base 2 e da base 2 a base 16 Problema: convertire un numero senza segno da base 8 a base 2. Soluzione: convertire indipendentemente ogni singola cifra del numero in base 8 in tre bit. Problema: convertire un numero senza segno da base 16 a base 2. Soluzione: convertire indipendentemente ogni singola cifra del numero in base 16 in 4 bit. Conversioni rapide Esempio: (766401)8 corrisponde a (111 110 110 100 000 001)2 7 6 6 4 0 1 Esempio: (A01F)16 corrisponde a (1010 0000 0001 1111)2 A 0 1 F Conversioni rapide Problema: convertire un numero senza segno da base 2 a base 8. Soluzione: raggruppare, da destra verso sinistra, i bit del numero in base 2 in gruppi di 3 bit e convertire indipendentemente ogni singolo gruppo di bit in una cifra ottale. Problema: convertire un numero senza segno da base 2 a base 16. Soluzione: raggruppare, da destra verso sinistra, i bit del numero in base 2 in gruppi di 4 bit e convertire indipendentemente ogni singolo gruppo di bit in una cifra esadecimale. Conversioni rapide Esempio: (10101011)2 corrisponde a (2 010 5 101 3)8 011 Esempio: (1110101011)2 corrisponde a ( 3 0011 A 1010 B )16 1011 Codifica dei dati numerici • Codifica dei numeri interi (bisogna codificare numero e segno) 0, ±1, ±2,±3,±4,... • Due metodi: • codifica con modulo e segno • codifica in complemento a due Modulo e segno • Codifica del segno seguita dalla codifica del valore assoluto • Si utilizza il primo bit (bit più significativo) per codificare il segno: 0 codifica “+”, 1 codifica “-” • I restanti bit si utilizzano per codificare il valore assoluto (i.e. numero senza segno) Modulo e segno -10 (su 5 bit) -10 (su 7 bit) 1 1 0 1 0 1 0 0 1 0 1 • Considerando n bit, questa codifica permette di rappresentare i numeri interi da -(2 n-1 -1) a (2 n-1 -1) 0 Modulo e segno • Problema: doppia rappresentazione dello 0 (+0 e -0!) • spreco di spazio (si sprecano due successioni di bit per codificare lo stesso valore) • gestione delle operazioni di controllo e aritmetiche più complessa +0 0 0 0 0 -0 1 0 0 0 Somme e sottrazioni in base 2 + 0 1 0 0 1 1 1 0 (riporto 1) - 0 1 0 0 1 (prestito 1) 1 1 0 Esempi 10111011 + 11010011 110001110 10111011 + 1 10111100 10111011 10000101 10000000 1 00110110 01111111 Complemento a 1 Dato un numero binario (X)2 , il complemento a 1 di (X)2 è un numero binario (Y)2 che si ottiene invertendo i bit di (X)2. Esempio: il complemento a 1 di (00111011)2 è (11000100)2 Complemento a 2 • Unica rappresentazione dello 0! • Data una successione di n bit, per codificare un numero intero X, si utilizza il valore binario corrispondente a (2n+X). • Es: codifica su 4 bit => 24=16 +6 = 16+6 = +22 => 10110 -6 = 16-6 = +10 => 1010 0 1 1 0 1 0 1 0 Complemento a 2 • Fatti: • il bit più significativo di un numero positivo in complemento a due è sempre 0 • il bit più significativo di un numero negativo in complemento a due è sempre 1 • Considerando n bit, questa codifica permette di rappresentare i numeri interi da • -2n-1 a (2n-1-1) Problema: dato un numero intero codificato in complemento a due, determinare il corrispondente valore in base 10 Complemento a 2 Problema: Convertire un numero codificato in complemento a 2 (X)2 nel corrispondente valore decimale. Soluzione: Se (X)2 >= 0 stesso procedimento della codifica modulo e segno Se (X)2 < 0 1. Calcolare il complemento a 1 di (X)2 e chiamarlo (Y)2 2. Sommare 1 a (Y)2, convertire in decimale il risultato, e chiamarlo (Z)10 3. Il valore corrispondente è -(Z)10 Esempi Caso numero negativo Il valore decimale di (1011)2 è (-5)10 infatti... complemento a 1 0100 + 1 0101 e convertendo (0101)2 si ottiene 5. Caso numero positivo Il valore decimale di (0011)2 è (+3)10 infatti... convertendo (011)2 si ottiene 3. Compressione dei dati • Finora non abbiamo valutato il costo e l’efficienza delle codifiche scelte. • La compressione dei dati permette di ridurre il numero di bit necessari alla codifica di un insieme di elementi di informazione. • costo di memorizzazione minore • trasmissione dati più veloce Esempio • supponiamo di avere l’alfabeto A={A,C,G,T} e una successione S di 1.000.000 di caratteri scelti in A. • Possibile codifica binaria dell’alfabeto: A=00, C=01, G=10, T=11 => la codifica di S prevede l’uso di 2.000.000 di bit. • Altra possibilità: assegnare codici binari (non ambigui!!) di lunghezza variabile agli elementi dell’alfabeto, in base alla loro frequenza relativa rispetto a S (più la frequenza è alta, più il codice sarà corto). Se A si presenta in S il 50% dei casi, C il 25%, G e T il 12.5%, allora, per esempio, A=0, C=10, G=110, T=111 in questo caso, la codifica di S risulta più corta, infatti (1*0.5+2*0.25+3*0.125+3*0.125) bit/carattere * 1.000.000 carattei = 1.750.000 bit • Compressione dei dati due tipi di algoritmi di compressione • lossless (senza perdita di informazione) • • • tutta l’informazione è importante e non si può perdere! Es: slide precedente, documenti word, programmi eseguibili,... lossy (con perdita di informazione) • si è disposti a perdere informazione pur di ottenere un maggior tasso di compressione • Es.: formati per immagini (JPEG, GIF,...), formati audio (MP3), formati video (famiglia MPEG) Il calcolatore • È un sistema complesso costituito da un numero elevato di componenti. • è strutturato in forma gerarchica • ogni livello di descrizione è caratterizzato da una struttura rappresentante l’organizzazione dei componenti del livello • ogni componente è caratterizzato dalla funzione che deve svolgere. Funzioni • Le funzioni svolte da un calcolatore sono classificabili in 4 tipologie: • elaborazione dati • memorizzazione dati • trasferimento dati • controllo Proprietà • Alcune proprietà • flessibilità nel calcolo (general-purpose) • modularità della struttura • componentistica scalabile e standard • semplicità di installazione • larga disponibilità di SW a basso costo Architettura di riferimeto • Architettura di Von Neumann • sottosistema di interfaccia • sottosistema di elaborazione • sottosistema di memorizzazione • canale (bus) di connessione Sottosistema di interfaccia • Permette di far interagire il calcolatore con il mondo esterno. • dispositivi di ingresso/uscita (unità periferiche) gestiti mediante interfacce che controllano il trasferimento dei dati • Schermo, tastiera, mouse, memoria di massa,... Sottosistema di elaborazione • il cuore (cervello!) del calcolatore è la CPU (Central Processing Unit). • Gestisce le funzioni di • controllo e coordinamento • elaborazione dei dati • Fisicamente è rappresentato dal microprocessore Sottosistema di memorizzazione • Per la memorizzazione dei dati è presente un’unità chiamata memoria. • Può essere vista come una serie di celle adiacenti, ognuna delle quali è identificata mediante un indirizzo (memory address). Canale di connessione • La connessione dei sottosistemi avviene mediante una linea per il trasferimento dati chiamata bus. • Problema: il collegamento contemporaneo di tutti le unità può essere difficilmente gestibile. • Soluzione: tecnologia master-slave • la gestione dell’intero sistema di comunicazione affidata a un master (la CPU) il quale gestisce l’accesso al bus • le unità periferiche rivestono il ruolo di slave, non possono accedere al bus autonomamente • si evitano possibili collisioni fra dati Pregi e difetti del collegamento a BUS semplicità estendibilità standardizzabilità lentezza limitata capacità sovraccarico della CPU Il BUS • È suddiviso funzionalmente in 3 componenti: • bus dati => trasferimento dati • • CPU <=> memoria CPU <=> interfacce di ingresso/uscita • bus indirizzi => trasferimento degli indirizzi di memoria in cui la CPU va a leggere e scrivere • bus di controllo =>trasferimento di informazione di controllo per coordinare l’intero sistema • • gestione della politica master-slave direzione dello scambio (lettura/scrittura) Esecuzione di un programma • un calcolatore basato sull’architettura di Von Neumann esegue un programma sulla base dei seguenti principi: • dati e programmi sono memorizzati in una memoria unica • i dati sono indirizzati in base alla loro posizione, indipendentemente dalla loro natura • le istruzioni vengono eseguite in modo sequenziale Il linguaggio macchina • il linguaggio per cui la CPU si comporta da esecutore è il linguaggio macchina (o linguaggio assembly). • È un linguaggio a basso livello • • • numero di operazioni ridotto numero di operandi ridotto non esiste il concetto di tipo di dato • L’utilizzo di tale linguaggio implica un’ottima conoscenza della struttura fisica del calcolatore • ogni CPU è caratterizzata dal suo linguaggio macchina (set di istruzioni) il ciclo fetchdecode-execute • Nell’esecuzione di un programma, la CPU opera ciclicamente nel seguente modo: • acquisizione dalla memoria di un’istruzione del programma (fase di fetch) • identificazione dell’istruzione fra quelle che compongono l’insieme delle istruzioni (fase di decode) • esecuzione dell’istruzione (fase di execute) Struttura di una CPU • Una CPU è costituita da 3 sottosistemi principali • l’unità aritmetico-logica (ALU), la cui funzione è di effettuare operazioni aritmetiche (somme, sottrazioni,...) e logiche (AND, OR,...). • i registri: celle di memoria interne alla CPU, utilizzate per memorizzare gli operandi delle operazioni aritmetiche e informazioni di controllo • l’unità di controllo (CU), che ha funzione di coordinamento Alcuni registri • Tra i vari tipi di CPU, il numero e il tipo di registri è variabile. Sono però sempre presenti i seguenti: • PC (Program Counter) contiene l’indirizzo di memoria della prossima istruzione da eseguire • IR (Instruction Register) contiene una copia dell’istruzione da eseguire • MAR (Memory Address Register) contiene l’indirizzo di memoria dove scrivere o leggere un dato • MDR (Memory Data Register) contiene una copia del dato da trascrivere o estratto dalla memoria. • PSW (Process Status Word) contiene informazioni inerenti allo status del sistema a seguito dell’esecuzione di un istruzione FETCH Ciclo F-D-E nel dettaglio • La CU fornisce alla memoria l’indirizzo della cella contenente l’istruzione da eseguire, la richiesta viene eseguita mediante la scrittura di tale indirizzo nel registro MAR e l’attivazione di un messaggio di controllo “LEGGI” sul BUS. • La memoria seleziona la cella contenente l’istruzione e la invia al registro MDR. La CU copia dal MDR al IR l’istruzione corrente. Ciclo F-D-E nel dettaglio DECODE • La CU incrementa il PC in modo che punti alla prossima istruzione da eseguire. • La CU esamina l’istruzione in IR e determina l’operazione da svolgere Ciclo F-D-E nel dettaglio EXECUTE • Le unità interessate all’esecuzione dell’istruzione vengono opportunamente comandate. Si provvede a prelevare eventuali operandi dalla memoria (fetch degli operandi) e a trasferire il risultato in un registro o in memoria Coordinamento delle attività • il ciclo F-D-E richiede che le varie unità operino in modo coordinato anche dal punto di vista della temporizzazione degli eventi. • Si introduce un orologio (CLOCK) che fornisce una cadenza temporale per la sincronia delle singole attività • La frequenza del clock (numero di attività elementari nell’unità di tempo) è un parametro per valutare la velocità di una CPU. Le CPU attuali hanno una frequenza di CLOCK dell’ordine del GHz (1000000 di operazioni al secondo). Prestazioni di un sistema • Parametri valutabili • tempo di risposta o di latenza (cioè il tempo che trascorre dall’inizio alla fine di un compito) • throughput (ammontare del lavoro svolto in un dato tempo) Prestazioni di un sistema • Si può misurare il tempo complessivo necessario al completamento di un compito (elapsed time), che comprende l’accesso al disco, alla memoria, attività di I/O, tempo di CPU,... • • è influenzato dagli altri processi attivi, in particolare dal sovraccarico apportato dal sistema operativo Tempo effettivo di elaborazione (tempo di CPU), non comprende il tempo di attesa dovuto alle operazioni di I/O e all’esecuzione di altri processi. Tempo di CPU tCPU= nCK * TCK tCPU: tempo di CPU nCK: numero di cicli di CLOCK necessari al completamento del processo TCK: periodo di CLOCK oppure tCPU= nCK / fCK tCPU: tempo di CPU nCK: numero di cicli di CLOCK necessari al completamento del processo fCK: frequenza di CLOCK Tempo di CPU Consideriamo nI numero di istruzioni che vengono eseguite CPI = nCK / nI CPI: numero medio di cicli di CLOCK per istruzione Quindi, tCPU= CPI * nI * TCK Oppure, tCPU= (CPI * nI) / fCK Tempo di CPU tCPU= (CPI * nI) / fCK Il tempo di CPU è influenzato da 1. frequenza di CLOCK 2. numero medio di cicli di CLOCK per istruzione 3. numero di istruzioni CISC vs RISC • Due filosofie di progettazione dei processori • CISC (complex instruction set computer) • RISC (reduced instruction set computer) Tipo di CPU CISC RISC CPI alto basso nI basso alto fCK media alta C-RISC soluzione intermedia! Altri indicatori • Il tempo di CPU è generalmente il parametro più importante nella valutazione delle prestazioni di un sistema informatico • Ci sono comunque altri indicatori • • MIPS (Mega Instructions per Second) MFLOPS (Mega Floating Point Operations per Second) La memoria • Due tipologie: • Memoria centrale • • contiene i programmi in esecuzione e i relativi dati, la velocità di accesso incide fortemente sulle prestazioni del sistema. Memoria di massa • destinata a contenere grandi quantità di dati che non vengono utilizzati frequentemente, ma che devono essere mantenuti in modo persistente. Altra tassonomia • Un’ulteriore classificazione può essere la seguente • memoria interna alla CPU (i registri) • memoria esterna alla CPU ma interna al calcolatore (memoria centrale) • memoria esterna al calcolatore (memoria di massa) Criteri di valutazione • Velocità di accesso • Capacità • Volatilità • Costo per bit Tipi di memoria • La realizzazione delle unità di memoria si basano su diverse tecnologie: • memorie elettroniche • memorie magnetiche • memorie ottiche Memorie elettroniche • sono caratterizzate • da un’alta velocità (d’accesso ai dati) • da una discreta capacità • dalla necessità di essere continuamente alimentate (memorie volatili) • da un alto costo per bit Memorie magnetiche • Sono caratterizzate • da un basso costo per bit • da una bassa velocità di accesso • da grandi capacità • dalla capacità di mantenere le informazioni in assenza di alimentazione (memorie non volatili) Memorie ottiche • hanno proprietà analoghe a quelle delle memorie magnetiche • • sono in genere caratterizzate da supporti non riscrivibili • negli ultimi anni sono nati dispositivi magneto-ottici, che consentono di modificare le informazioni memorizzate. adatte a memorizzare grandi quantità di dati, ma non alla memorizzazione di dati da elaborare. Memorie centrali e di massa • Memorie centrali => basate su tecnologie elettroniche. Sono veloci, volatili, noon molto grandi e costose • Memorie di massa => basate su tecnologie magnetiche ed ottiche. Sono lente, molto capaci, poco costose e non volatili. • Allo stato attuale • le memorie centrali sono 5 ordini di grandezza più veloci delle memorie di massa • le memorie centrali sono due ordini di grandezza più costose delle memorie di massa La memoria centrale • Può essere vista come una successione di elementi binari (bit) che sono in grado di assumere solo due stati (convenzionalmente, 0 o 1). • I bit sono raggruppati in unità minime di 8, 16, 32 o 64 bit, dette celle. • Ogni sequenza di bit avente la lunghezza di una cella è detta parola. • Ogni cella possiede un indirizzo che rappresenta la sua posizione rispetto alla prima cella, la quale convenzionalmente ha indirizzo 0. • la dimensione massima della memoria indirizzabile dipende dipende dal numero di bit a disposizione per codificare gli indirizzi di cella. Ossia, k bit per cella => 2k indirizzi possibili. La memoria centrale • Dal punto di vista dell’esecuzione delle istruzioni, la memoria centrale è un oggetto monolitico al quale si accede mediante i registri MAR e MDR e a un insieme di segnali di controllo (leggi/ scrivi). • La lettura di una parola, residente in una cella, avviene rendendo disponibile sul bus dati (e dunque nel MDR) la parola presente nella cella selezionata attraverso il suo indirizzo. Il contenuto della cella non viene modificato. • La scrittura di una parola (residente nel MDR) in una cella avviene copiando il contenuto del MDR nella cella indirizzata (l’indirizzo si trova nel MAR). Prestazioni della memoria • Le prestazioni di una memoria si possono valutare secondo i seguenti parametri: • tempo di accesso: intervallo di tempo necessario per completare un’operazione di scrittura/lettura • ciclo di memoria: è valutato sommando il tempo d’accesso all’intervallo di tempo necessario per effettuare una nuova operazione di scrittura/lettura. Legato a fattori tecnologici. misurato in numero di accessi su unità di tempo • velocità di trasferimento: quantità di dati trasferiti nell’unità di tempo (misurata in bit/s o byte/s). Metodi di accesso • Dato l’indirizzo della cella da leggere o scrivere, si possono individuare le seguenti tipologie di accesso: • Accesso sequenziale: le celle sono poste in successione. La lettura di un dato comporta la lettura di tutti i dati precedenti. (Esempio: nastri magnetici). Il tempo di accesso è molto variabile, dipende dalla posizione del dato nel supporto. • Accesso casuale: l’accesso a una cella non richiede la lettura delle precedenti. Il tempo d’accesso è indipendente dalla posizione del dato e può essere considerato costante. La memoria centrale è caratterizzata da un accesso casuale, è anche detta memoria RAM (Random Access Memory). Metodi di accesso • Accesso misto: L’indirizzo di una cella non consente di identificare con precisione la posizione fisica del dato sul supporto. Vengono effettuati una serie di accessi per giungere in prossimità del dato e successivamente una ricerca sequenziale per identificare con precisone la posizione del dato. Esempio: unità a dischi. Tempo di accesso variabile. • Accesso associativo: Il contenuto di una cella non è selezionato in base all’indirizzo, ma in base a parte del contenuto della cella stessa. E’ una sorta di accesso di tipo casuale, infatti il tempo di accesso è costante. Esempio: memoria cache. Sono memorie molto veloci e particolarmente costose. Memoria ROM • Generalmente le memorie di tipo elettronico sono volatili. Esistono comunque delle memorie basate su tecnologie elettroniche di tipo non volatile: • • memorie ROM (Read-Only Memory): possono essere lette ma non modificate. Sono usate per memorizzare permanentemente le informazioni di inizializzazione del calcolatore. Negli ultimi anni si sono diffuse le memorie FLASH, le quali sono memorie di tipo elettronico, non volatili e riscrivibili. Generalmente sono di piccole dimensioni e piuttosto costose. Organizzazione della memoria • La memoria è divisa su almeno due livelli. • • • Memoria di livello superiore: piccola, veloce e costosa Memoria di livello inferiore: grande, lenta e a buon mercato La memoria di livello superiore contiene un sottoinsieme dei dati e dei programmi residenti nella memoria di livello inferiore. • Quando si cerca una parola, si cerca prima nella memoria di livello superiore e poi nella memoria di livello inferiore. Nel caso si trovi nel primo livello, l’accesso al dato sarà rapido, in caso contrario lento. • Un organizzazione di questo genere è efficiente solo se esiste un buon criterio per scegliere quali dati devono essere trasferiti dalla memoria lenta a quella veloce. Organizzazione della memoria • È necessario prevedere con una certa precisione il comportamento dei programmi. • Statisticamente, un programma indirizza il 90% delle richieste di lettura/scrittura a un’area di memoria contigua inferiore al 10% dell’area complessiva. • Località spaziale: quando un programma fa riferimento a un dato, è molto probabile che faccia riferimento a un dato fisicamente vicino nell’immediato futuro. • Località temporale: quando un programma fa riferimento a un dato, è molto probabile che si riutilizzi nell’immediato futuro. Principio di località • Principio di Località: le informazioni usate di recente e quelle in posizioni contigue saranno utilizzate con molta probabilità nell’immediato futuro. • Se si favorisce l’accesso a tali informazioni (precaricandole nella memoria di livello superiore), si migliorano le prestazioni del sistema. • Se la memoria di livello superiore è già piena (di solito è di piccole dimensioni), le informazioni che soddisfano il principio di località vanno a sostituire un blocco di memoria di livello superiore, i cui dati non sono stati recentemente utilizzati (Least Recently Used Policy, LRU). Organizzazione reale • Generalmente ci sono più di due livelli. Registri Memoria Cache Memoria RAM Dischi magnetici Nastri Dispositivi di memoria di massa • Nastri magnetici • • sono dispositivi ad accesso sequenziale • informazioni scritte e lette a blocchi chiamati record fisici, separati tra loro da spazi chiamati gap. • Dispositivi economici, lenti, ma di grandi capacità. Utili per i backup. le operazioni di lettura/scrittura sono effettuate mediante una testina che può rilevare e modificare lo stato di magnetizzazione del nastro Dispositivi di memoria di massa • Dischi magnetici • • sono dispositivi ad accesso misto • per poter utilizzare un disco, si deve dapprima organizzarlo in settori e tracce mediante l’operazione di formattazione. • per leggere e scrivere dei dati è necessario fornire alla testina numero di traccia e numero di settore. • tipiche unità a dischi: floppy disk, hard disk. l’informazione memorizzata in anelli concentrici detti tracce. In ogni traccia è memorizzata la stessa quantità di informazione (=> densità variabile di memorizzazione). Ogni traccia è suddivisa in settori. Settori e tracce sono separati da gap. • Dispositivi di memoria di massa Dischi ottici • • • sono generalmente dispositivi non riscrivibili (CD-ROM) • oggigiorno esistono anche dischi ottici che permettono di essere riscritti più volte: CD-RW (Rewritable) • DVD: dischi ottici di ultima generazione, memorizzano fino a 17 GByte di informazione. I normali CD-ROM arrivano a 800 MByte. permettono di memorizzare grandi quantità di dati. i dati sono memorizzati rendendo opache o lucide le zone del disco (0 o 1). La lettura avviene mediante un raggio laser che esplora la superficie e identifica il valore dei bit in base alla riflessione o meno del raggio. L’informazione è organizzata in un unico percorso a spirale. => accesso sequenziale, che comunque risulta essere piuttosto veloce. Interfacce di I/O • il calcolatore comunica con l’ambiente esterno (le periferiche) mediante delle interfacce di ingresso/uscita, che hanno il compito di tradure i segnali che giungono dal calcolatore in informazioni comprensibili alle periferiche e vice versa. • La trasmissione dei dati può essere • • • seriale (l’informazione è trasmessa un bit per volta) parallela (più bit trasmessi in parallelo) Alcuni standard • • RS-232C, USB, FireWire (tx seriale) Centronics (tx parallela) Interfacce di I/O • Ogni interfaccia di I/O è dotata almeno dei seguenti registri • Registro dati, utilizzato per scambiare i dati tra periferica e calcolatore. Connesso con il bus dati. • Registro di stato (o di controllo), nel quale transitano informazioni di controllo necessarie alla sincronizzazione tra CPU e periferica. Connesso con il bus di controllo. Sincronizzazione • Periferiche e CPU hanno generalemnte diverse velocità e necessitano di sincronizzazione. • Ci sono tre diversi metodi di sincronizzazione: • • • a controllo di programma a interruzione con accesso diretto alla memoria Sync. a controllo di programma • • La sincronizzazione è completamente gestita dalla CPU. • Esempio: stampa di una linea di caratteri mediante una stampante, ogni singolo carattere viene trasferito alla stampante mediante il registro dati, solo quando un carattere è stato stampato viene trasferito nel registro dati il seguente. • • Vantaggio: è una gestione della sincronizzazione semplice. La CPU esegue un ciclo (detto ciclo di polling) che ispeziona/scrive periodicamente il registro dati. Svantaggio: rischio di sovraccarico della CPU Sync. a interruzione • Elimina il problema di sovraccarico della CPU tipico della sincronizzazione a controllo di programma. • Ogni interfaccia è dotata della possibilità di notificare il suo status alla CPU mediante un segnale chiamato interruzione (o interrupt). • Quando la CPU riceve un interrupt, interrompe la sua attività ed esegue un programma di risposta all’interruzione per gestire la comunicazione con l’interfaccia (e quindi con la periferica). • La CPU è occupata solo per il trasferimento dei dati. (si evitano i tempi di attesa del ciclo di polling) Sync. con accesso diretto alla memoria • Se si hanno grossi e frequenti trasferimenti di dati, la gestione della sincronizzazione mediante interrupt rischia di essere inefficiente. • Esistono delle componenti HW chiamate DMA (Direct Memory Access) che sostituiscono la CPU nella gestione del trasferimento dati. • La CPU controlla i DMA, comunica loro solo l’indirizzo di memoria da cui leggere o sul quale scrivere e la quantità di dati da trasferire, dopodiché il DMA gestisce l’intero processo di trasferimento. • Nelle architetture più sofisticate i DMA sono processori dedidati all’input/output. Infrastrutture Software • I componenti fisici di un sistema informatico sono resi accessibili agli utenti attraverso un complesso di strumenti software finalizzati all’utilizzo dell’architettura. • Si tratta di Software (programmi) di base generalmente fornito insieme al Hardware. • L’insieme di tali programmi di base è indicato con il termine sistema operativo (S.O.). Le funzioni del S.O. • Il S.O. è un interfaccia tra l’utente e l’hardware che facilita l’utilizzo delle risorse di un sistema. In particolare deve svolgere le seguenti funzioni: • • • • • • esecuzione di applicazioni accesso ai dispositivi di I/O archiviazione di dati e programmi controllo d’accesso contabilizzazione gestione dei malfunzionamenti Elementi di un S.O. • Generalmente l’insieme dei programmi costituenti il S.O. permette di gestire: • il processore (quali programmi eseguire e quali compiti assegnare alla CPU, traduzione dei programmi ad alto livello al linguaggio assembly mediante il supporto di compilatori e interpreti) • la memoria (allocazione della memoria per i diversi programmi in esecuzione, definizione di zone riservate di memoria per l’archiviazione dei dati dei programmi) • le periferiche (accesso ai dispositivi di I/O, si mascherano i dettagli di basso livello, gestione dei conflitti) Elementi di un S.O. • il file system (archiviazione e reperimento dei dati in memoria di massa) • gli utenti e i relativi interpreti comandi (accesso semplice alle funzionalità disponibili) I gestori di memoria, processore, file system, periferiche e utenti interagiscono fra loro per coordinare l’accesso alle risorse da parte di utenti e SW applicativo. Programmi applicativi • Sono programmi utilizzati dall’utente per svolgere attività di alto livello (elaborazione di testi e grafica, giochi, fogli di calcolo,...) • non fanno parte dei programmi del S.O. In particolare, • possono far riferimento ad un set ristretto di istruzioni del processore (modalità utente vs modalità supervisore) • non possono decidere autonomamente quando e come avere accesso alle risorse. È il S.O. stesso a fornire loro l’accesso alle risorse. Tassonomia degli utenti • Gli utenti di un S.O. possono • programmatori di sistema • amministratori di sistema • utenti applicativi essere Un po’ di storia dei S.O. • sistemi senza S.O: i programmi applicativi dovevano anche contenere delle istruzioni per la gestione a basso livello dei dispositivi fisici. • I programmi erano caricati in memoria tramite un dispositivo di I/O in grado di leggere schede perforate contenenti la codifica in linguaggio macchina di dati e programmi. • Pessima gestione delle risorse: si doveva prenotare la macchina al fine di stabilire un ordine di esecuzione dei programmi (Job). • • La macchina consentiva l’esecuzione di un solo programma alla volta. Perdita di tempo per la preparazione dell’ambiente di supporto all’esecuzione. • Un po’ di storia dei S.O. Sistemi batch (o a lotti): sono dotati di una componente software (un S.O. molto rozzo) chiamata monitor in grado di automatizzare l’esecuzione dei programmi. Il monitor è dotato di un linguaggio di controllo chiamato Job Control Language. • • Si esegue un lotto di programmi (jobs) alla volta. • • Efficiente utilizzo delle risorse Non c’è nessuna interazione con l’utente. (ottimi per attività con bassa interazione: esempio stampa estratti conto). Tempi di attesa notevoli per ottenere i risultati dell’elaborazione (si deve attendere la terminazione dell’esecuzione di un intero lotto di job). Un po’ di storia dei S.O. • Nei primi sistemi informatici mancava • • • interattività • gestione dell’input/output i programmatori dovevano scriversi le loro funzioni a basso livello per l’input e l’output) • sfruttamento parallelo delle risorse protezione della memoria (evitare interferenze fra programmi in memoria) temporizzazione dell’esecuzione (al fine di evitare il monopolio dell’intero sistema da parte di un solo programma) Un po’ di storia dei S.O. • • sistemi uniprogrammati • in memoria può risiedere al più un programma (processo) oltre al S.O. • • es. MS-DOS ridotto uso della CPU sistemi multiprogrammati (time-sharing) • • • più progammi contemporaneamente in memoria oltre al S.O. es. Windows, MacOS, Unix,... Uso più efficiente della CPU Un po’ di storia dei S.O. • Nei primi sistemi informatici mancava • • • interattività • gestione dell’input/output i programmatori dovevano scriversi le loro funzioni a basso livello per l’input e l’output) • sfruttamento parallelo delle risorse protezione della memoria (evitare interferenze fra programmi in memoria) temporizzazione dell’esecuzione (al fine di evitare il monopolio dell’intero sistema da parte di un solo programma) Processi • Nei sistemi attuali, più copie dello stesso programma si possono eseguire concorrentemente. • Processo = copia di un programma in esecuzione + dati necessari all’esecuzione. • A un programma può corrispondere più di un processo (processi figli e processi padre, es. videoscrittura + stampa). • Un S.O. è un’infrastruttura SW di supporto all’esecuzione concorrente di più processi. Modelli organizzativi di S.O. • Ogni S.O. può essere caratterizzato funzionalmente da • un nucleo (kernel) • un insieme di processi di servizio. • Modello monolitico vs modello a strati Modello monolitico • Il S.O è costituito da un unico processo kernel che provvede alla gestione di tutti i servizi di tutte le risorse del sistema (processore, memoria, periferiche, file system, ...) • gli utenti e i processi applicativi interagiscono con il kernel attraverso l’esecuzione di servizi (chiamate di sistema). • si hanno due modalità di funzionamento • modalità utente: i processi eseguiti in questa modalità non possono accedere a tutte le risorse liberamente. Es. vietato interagire direttamente con i dispositivi di I/O. • modalità supervisore (kernel mode): usata dal kernel per implementare le funzionalità necessarie. Nessun limite nelle operazioni effettuabili. Modello a strati • consiste in un nucleo piuttosto semplice che gestisce solamente il processore e l’esecuzione dei processi. Interagisce direttamente con l’hardware. • Una serie di processi di servizio standard organizzati su diversi livelli (macchine virtuali). • • ogni processo di un livello implementa delle funzionalità facendo uso dei servizi messi a disposizione dal livello inferiore È un’organizzazione che favorisce la portabilità del S.O. su diverse architetture HW. Modello a strati Applicazione (Editor) Interprete dei Comandi Applicazione (Foglio Elettronico) File System Periferiche Memoria Nucleo HW Applicazione (EMail) Applicazione (Browser) Applicazione (Data Base) Applicazione (Word Processor) Traduzione dei programmi • La CPU si comporta da esecutore per programmi scritti in linguaggio macchina (assembly) • • E’ un linguaggio a basso livello difficile da usare. Soluzione: usare un linguaggio L di alto livello più potente ed espressivo. Utilizzare degli opportuni software per tradurre i programmi scritti in L in programmi assembly. • • Interpreti Compilatori Gestione dei processi • Nelle architetturre HW moderne si tende ad elaborare l’informazione in maniera parallela. • 3 livelli di parallelismo • • • parallelismo a livello di dati parallelismo a livello di istruzioni parallelismo a livello di programmi • i primi due livelli di parallelismo sono gestibili solo mediante architetture HW parallele (molte CPU), il modello di Von Neumann può implementare solo il parallelismo a livello di programmi. • il gestore dei processi ha il compito di implementare in maniera efficiente il parallelismo a livello di programmi. • • • Gestione dei processi Il componente in grado di eseguire i processi è la CPU (processore) Se abbiamo un unico processore il parallelismo è simulato. Un processo può trovarsi in un uno dei seguenti stati: • in esecuzione: ovvero il processo ha a disposizione il processore per l’esecuzione del proprio codice • pronto: ovvero il processo è in grado e in attesa di essere eseguito, non appena il processore diviene disponibile (i processi in questo stato vengono generalmente posti in coda, FIFO policy) • in attesa: ovvero il processo non è in grado di essere eseguito perché in attesa di qualche evento esterno (es. input da tastiera) Evoluzione di un processo 1. il processo viene creato e messo nella coda dei processi pronti 2. il primo processo nella coda dei processi pronti viene posto in stato di esecuzione; se la coda era inizialmente vuota, il processo in esecuzione coincide con quello creato al punto precedente 3. il processo in esecuzione ha la piena disponibilità del processore fino al verificarsi di uno dei seguenti eventi: a. scade il quanto di tempo a disposizione del processo; il processo viene rimesso nella coda dei processi pronti b. il processo effettua un’operazione I/O; il processo è messo in stato d’attesa c. il processo termina 4. in base a quale evento si è verificato in 3, il processo evolve nel seguente modo: a. il processo attenderà il suo turno nella coda per essere nuovamente eseguito b. il processo viene rimesso nella coda dei processi pronti, una volta che l’operazione di I/O è terminata c. il processo è rimosso dall’elenco dei processi esistenti • Problemi del parallelismo Morte per fame (Starvation): un processo in stato di pronto non viene mai eseguito. • • non accade nel caso di politica FIFO, può accadere nel caso di utilizzo di code con priorità. Blocco critico (Deadlock): un insieme di processi rimane permanentemente bloccato. Es. due processi A e B. A richiede i dati di B per essere eseguito, B richiede i dati di A per essere eseguito. Oppure, mai invitare 5 filosofi a cena!!! • • Tecniche di verifica statica per evitare deadlock Tecniche di eliminazione dei deadlock a runtime Gestione della memoria • Nei S.O. multiprogrammati possiamo avere molti processi in memoria centrale • Problema: la memoria centrale è tipicamente di piccole dimensioni (Max 1Gb). • Si rende necessaria l’implementazione di un gestore della memoria che scarichi in memoria di massa i processi poco utilizzati e che inoltre permetta di • ridurre la necessità di spazio mantenendo in memoria solo parte delle istruzioni e dei dati del processo. • ridurre la necessità di spazio condividendo il codice fra diversi processi che corrispondono allo stesso programma. (segmentazione della memoria: segmento codice, segmento dati) Gestione della memoria • il gestore della memoria permette di trasferire il contenuto di un’area di memoria centrale in un’area di memoria di massa chiamata memoria di swap. • si trasferiscono nell’area di swap i processi in attesa e alcuni dei processi in stato di pronto al fine di liberare memoria centrale. • Per lo scarico nell’area di swap si segue il principio di località. Gestione della Memoria • La politica migliore per la gestione della memoria prevede di scaricare la pagina che sarà utilizzata il più tardi possibile. Soluzione impossibile! • Approssimazioni dell’algoritmo ottimo: e.g. scaricare la pagina usata meno di recente (Least Recently Used - LRU). Gestione della Memoria • Altro problema: protezione della memoria. • Ad ogni processo è assegnata un’area di memoria distinta. Se un processo “invade” aree di memoria diverse, viene segnalata l’eccezione. Gestione delle periferiche • Il gestore delle periferiche mette a disposizione delle funzionalità di lettura/scrittura da/verso dispositivi periferici di alto livello, indipendenti dalla struttura HW delle periferiche. • Tali comandi di alto livello sono realizzati facendo uso di meccanismi HW e SW di basso livello quali • • driver (programmi SW destinati alla gestione delle periferiche) controller (interfacce di I/O HW per il trasferimento di dati gestiti generalmente via interrupt) Gestione delle periferiche • I driver permettono • • di astrarre le operazioni di lettura/scrittura • di virtualizzare la presenza di più periferiche (spooling) permettono di implementare operazioni di scrittura/lettura a basso livello affidabili (se un’operazione non va a buon fine viene ripetuta, nel caso in cui no sia possibile eseguirla viene segnalato il malfunzionamento) • esempio: la coda di stampa Il File System • È la componente del S.O. che si occupa della gestione della memoria di massa e dell’organizzazione logica dei dati • Le operazioni supportate da un file system sono: • • • • recupero dei dati precedentemente memorizzati eliminazione di dati modifica dei dati copia dei dati fra diversi dispositivi di memoria di massa Il File System • I dati sono memorizzati in contenitori logici detti file. Ogni file è identificato da un nome (il nome può essere affiancato da un’estensione che individua il tipo di file) • Per una miglior organizzazione dei dati, i file possono essere memorizzati in contenitori detti directory o cartelle. • il file system è generalmente organizzato secondo una struttura ad albero. • Possiamo individuare un file fornendo il percorso assoluto o relativo all’interno dell’albero del file system. • L’accesso all’informazione può avvenire attraverso opportuni comandi testuali o grafici Organizzazione fisica dei dati • I file sono memorizzati sul supporto fisico (dispositivi di memoria di massa) in blocchi di piccole dimensioni. • I blocchi potrebbero essere non contigui! • Due tecniche di memorizzazione • File Allocation Table (FAT) • I-nodes FAT • L’associazione tra nome del file e blocchi fisici che contengono il file viene gestita mediante una lista concatenata: a partire dal primo blocco, in coda ad ogni blocco di dati viene riportato il successivo. • Tale struttura viene memorizzata in un’area del disco chiamata FAT (File allocation Table) • Per ogni file, nella FAT è mantenuto un descrittore di file contenente i seguenti dati • • indirizzo del primo blocco del file data e ora di modifica, dimensioni,... • L’organizzazione mediante FAT funziona bene per file di piccole dimensioni • Usata in Windows 95/98 I-NODES • L’organizzazione in blocchi è basata su delle strutture dati chiamate i-node, le quali possono mantenere sia informazioni inerenti al descrittore del file sia inerenti ai blocchi di dati. • Un i-node può contenere informazioni inerenti ai blocchi di dati quando il file è piccolo, altrimenti può indicare insiemi di altri inode. • Ai file di grandi dimensioni è associato un albero di i-nodes, le cui foglie contengono i riferimenti ai blocchi di dati. • • La struttura ad albero rende più efficiente l’accesso ai dati. È una metodologia di memorizzazione tipicamente usata nei sistemi UNIX. La frammentazione • Frammentazione esterna: in caso di allocazione contigua dei file è necessario avere un numero di blocchi liberi contigui pari al numero di blocchi del file da memorizzare. FAT e I-Nodes risolvono questo problema in quanto non prevedono allocazione contigua dei dati. • Frammentazione interna: un file deve comunque occupare uno spazio pari ad un multiplo intero della dimensione dei blocchi. Problema non risolvibile né con FAT né con I-Nodes. Controllo degli accessi • I S.O. multiutente possiedono meccanismi di identificazione degli accessi al sistema. • La modalità più usata prevede di associare ad ogni utente un account (i.e. nome) e una password. • in questo modo è possibile • • • personalizzare l’ambiente operativo di ogni utente facilitare la distribuzione dei costi di gestione fornire una diversa visibilità del sistema a differenti tipi di utente Controllo degli accessi • Oltre a fornire un controllo sugli utenti è anche possibile stabilire un sistema di protezione dei file. • Esempio: nei sistemi Unix, si possono distinguere 3 tipi di utenti: il proprietario di un file, il gruppo di utenti a cui appartiene il propietario del file e il resto del mondo. • • Per ogni tipologia di utente possiamo abilitare le operazioni di lettura (R) del file, scrittura del file (W), esecuzione del file (X). Nei S.O. multiutente è anche possibile proteggere l’accesso alle varie risorse di sistema mediante le Access Control List (ACL), ovvero liste che specificano quali utenti possono utilizzare determinate risorse (Es. ad alcuni utenti può essere proibito l’uso di una stampante di rete) Le applicazioni • Le applicazioni (programmi applicativi) nascondono i dettagli di basso livello all’utente. • Un programma applicativo è composto da tre componenti fondamentali: • • sottosistema di interfaccia con l’utente (interfaccia utente): si incarica di cotrollare gli input dell’utente e presentare gli output dei risultati computati. Le interfacce possono essere grafiche o testuali. • sottosistema di logica applicativa: implementa gli algoritmi per la manipolazione di dati che caratterizzano l’applicazione • sottosistema di gestione dei dati: si occupa dell’organizzazione dei dati, in particolare reperimento e memorizzazione. Sono 3 sistemi indipendenti (gestione più semplice e rapida dello sviluppo del SW) Sviluppo delle applicazioni • Le applicazioni possono essere sistemi complessi. Dunque si devono progettare con cura • • la programmazione di un’applicazione è solo una fase nella catena di sviluppo del SW. Lo sviluppo di un SW può essere suddiviso nelle seguenti attività: • • • • • analisi e specifica dei requisiti progettazione sviluppo e test rilascio manutenzione Ciclo di vita del SW • L’insieme delle attività necessarie allo sviluppo di un’applicazione formano il ciclo di vita del software. • Il ciclo di vita del software può essere strutturato secondo diversi modelli: • • modello a cascata: attività svolte in sequenza • modello evolutivo: si opera in modo incrementale, iniziando a sviluppare le componenti più critiche del sistema e arrichendo via via il sistema di nuove funzionalità. modello a prototipi: si comincia lo sviluppo direttamente implementando dei prototipi Tipi di applicazioni • • Word processors: videoscrittura, elaborazione del testo • • Browser (per navigare in internet) • • per presentazioni • per la posta elettronica e altri tipi di servizi di rete spreadsheets (o fogli elettronici): per costruire tabelle, grafici e fare dei calcoli. Basi di dati (per memorizzare e reperire efficientemente l’informazione) per l’elaborazione grafica e video (fotoritocco, disegno, montaggio digitale...) Word Processors • si possono distinguere in due categorie • WYSIWYG (What You See Is What You Get): es. Word • non WYSIWYG: prevedono un linguaggio per la formattazione del testo, es. LaTeX. Esempio LaTeX $$E_1=\{e\mid e\in\cI^- \mbox{ and } \ll e\rr\not\in\bigcup_{\cI'\in \cA_1}\cI'\}$$ Reti di calcolatori Reti di calcolatori • Rete di calcolatori: insieme di calcolatori interconnessi mediante una rete di comunicazione. • Si possono distinguere • reti di calcolatori vere e proprie • • ogni calcolatore mantiene una propria indipendenza, gli utenti interagiscono in modo esplicito con la rete sistemi distribuiti • • gli utenti non hanno visibilità sull’architettura del sistema si presentano come sistemi omogenei progettati per eseguire un’applicazione particolare (Es: BANCOMAT) Finalità di una rete • condivisione di risorse (memoria di massa, stampanti, CDROM, ...) • comunicazione tra utenti (posta elettronica, file transfer,...) • miglioramento dell’affidabilità • risparmio attraverso la condivisione di risorse Classificazione • tecnologia di comunicazione • • • reti punto a punto reti multipunto (o broadcast) dimensione • Local Area Network (LAN): limitata estensione, calcolatori all’interno di un edificio • • Metropolitan Area Network (MAN): area urbana • reti di reti (internet working): collegamenti di più reti differenti mediante elementi di interfaccia Wide Area Network (WAN): ampie dimensioni, collegamenti anche intercontinentali Reti punto a punto • Ogni coppia di calcolatori è connessa mediante una linea di comunicazione dedicata • È una soluzione poco praticata perché • se i calcolatori da connettere sono fisicamente molto distanti, il costo della linea dedicata potrebbe essere molto elevato • se dei calcolatori devono essere collegati in modo non continuativo, l’uso di linee dedicate non ha molto senso ed è costoso • Nel caso si debbano connettere i calcolatori con modalità “tutti con tutti”, il numero di connessioni dedicate da creare è molto elevato. Reti Broadcast • Le reti broadcast sono caratterizzate da canali di comunicazione condivisi • Ogni calcolatore sulla rete è caratterizzato da un identificatore univoco (indirizzo di rete) • Ogni messaggio spedito da un calcolatore include l’indirizzo del destinatario. • Ogni messaggio spedito raggiunge tutti i calcolatori connessi, solo il calcolatore il cui indirizzo di rete corrisponde a quello contenuto nel messaggio riceve il messaggio. WAN • • Nel caso più generale una rete geografica (WAN) può essere rappresentata su 3 livelli: • rete di trasmissione: si occupa della trasmissione dell’informazione fra i diversi nodi (IMP - Interface Message Processors), instradamento, verifica della correttezza dei messaggi • rete di calcolatori (hosts): i calcolatori sono collegati agli IMP. Lo scopo è quello di eseguire le applicazioni. • rete degli utenti: comunicazione fra utenti, esecuzione di applicazioni distribuite in maniera trasparente Le reti organizzate secondo questi livelli sono chiamate reti commutate WAN • Le reti geografiche si classificano a seconda della strategia utilizzata per instradare i messaggi • commutazione di circuito • Viene inizialmente stabilita una connessione temporanea tra mittente e destinatario. Una volta che la connessione è stabilita, inizia il trasferimento dei dati. • Vantaggiosa nel caso in cui la comunicazione sia molto frequente e non si abbiano periodi di inattività della linea. (es. sistema telefonico). WAN • commutazione di pacchetto • il messaggio è frammentato in pacchetti di piccole dimensioni. Ogni pacchetto contiene l’indirizzo del destinatario e un numero progressivo che indica la posizione del pacchetto nel messaggio. • Vantaggi: uso dei canali più efficiente, possibilità di invio anche in caso di traffico elevato, gestione di diversi livelli di priorità • due metodi di instradamento • a datagrammi (spedizione dei pacchetti in maniera indipendente, anche su linee diverse) • a circuito virtuale (si stabilisce un cammino univoco tra mittente e destinatario per tutti i pacchetti). LAN • Obiettivo: connettere dispositivi fisicamente vicini => tecnologie diverse da quelle impiegate nelle WAN (tipicamente usano un approccio broadcast). • Le LAN sono generalmente • • • • veloci (canali di comunicazione con ampia capacità di banda) facilmente espandibili, modulari economiche affidabili LAN • Le LAN possono essere caratterizzate dalla loro topologia di rete, ossia dalla struttura delle loro connessioni • • topologia a bus (semplice, flessibile, economica, es: ethernet) • il guasto di un host non implica la disabilitazione dell’intera rete • svantaggio: unico mezzo di comunicazione, pessime prestazioni in caso di molto traffico topologia a stella (connessione punto a punto) • • controllo centralizzato delle risorse, ottime prestazioni rischio di sovraccarico del server, dipendenza dall’affidabilità del server LAN • Topologia ad anello: prevede una connessione circolare degli host • • • • possono avere dimensioni molto elevate limitata flessibilità, è difficile espanderla l’affidabilità della rete dipende dall’affidabilità di tutti gli host (soluzione: reti a doppio anello) Topologia Wireless: approccio broadcast • trasmissione basata su onde radio Internetwork • Una LAN non può crescere oltre una certa misura, se non al prezzo di un rilevante decadimento delle prestazioni. • Soluzione: connettere più LAN insieme (LAN estesa) mediante • • • repeater (se le LAN sono identiche) • router (per reti con schemi di indirizzamento distinti, ma stesso protocollo di rete) • gateway (per reti completamente incompatibili) switch (permette un maggior numero di tx in contemporanea) bridge (per filtrare i pacchetti e in caso di reti distinte ma con stesso schema di indirizzamento) Architettura del SW di rete • I calcolatori collegati in rete devono cooperare per stabilire una comunicazione e per poter trasmettere dei dati. • Le regole che formalizzano questa cooperazione sono chiamate protocolli di comunicazione. • Condividendo lo stesso protocollo due calcolatori possono comunicare. Protocolli di comunicazione • mediante i protocolli di comunicazione si specificano tra l’altro • • formati dei dati, struttura dei messaggi (pacchetti), velocità di trasmissione, come e quando comunicare... La comunicazione può essere piuttosto complessa, pertanto si specificano insiemi di protocolli, ognuno dei quali formalizza aspetti distinti della trasmissione. Ciò rende il progetto del SW di rete più semplice e flessibile Architettura di rete • Un’architettura di rete dovrebbe essere organizzata gerarchicamente seguendo i principi qui elencati • ogni protocollo formalizza un diverso livello di astrazione della comunicazione • le funzioni associate ad ogni livello sono ben definite e omogenee tra loro • scopo di ogni livello è di fornire servizi al livello superiore, mascherando il modo in cui sono implementati. Ogni livello è caratterizzato da una interfaccia con il livello superiore. • Le interfacce sono progettate in modo da minimizzare gli scambi tra un livello e l’altro Architettura a livelli • Consideriamo due processi (sorgente e destinazione), residenti su host distinti, che vogliono comunicare • ognuno dei due host è dotato di un insieme di protocolli organizzati su livelli. In entrambi gli host, i livelli devono essere organizzati in maniera compatibile. • La trasmissione avviene simulando la comunicazione tra livelli corrispondenti, seguendo le regole stabilite dal corrispondenti protocolli di livello. • Ogni protocollo è caratterizzato da sintassi, semantica e temporizzazione • Standard ISO/OSI Standard TCP/IP • È l’architettura a livelli che permette l’interoperabilità tra reti fisiche diverse. È semplice ed efficiente • • È lo standard de facto di Internet È un’archittettura basata su 5 livelli • • livello applicazione • • livello internet (implementato dal protocollo IP-Internet Protocol) livello di trasporto (implementato dal protocollo TCP-Transmission Control Protocol) livello di accesso alla rete livello fisico Standard TCP/IP • il livello fisico definisce l’interfaccia fisica tra stazione e mezzo di trasmissione • il livello di accesso alla rete si occupa dello scambio di dati tra un sistema finale e la rete. I dati sono organizzati in frame. • il livello internet si occupa di interfacciare sistemi su reti distinte (formato dei pacchetti e meccanismi per farli transitare attraverso uno o più router). • il livello di trasporto si occupa di garantire l’affidabilità della trasmissione dei dati • il livello applicazione specifica come le applicazioni possono utilizzare i servizi forniti dall’insieme di protocolli TCP/IP. Funzionamento di TCP/IP • • Ogni host individuato da un indirizzo univoco all’interno della rete. • Per poter comunicare con un processo in un host è necessario specificare l’indirizzo del host e la porta del processo. Ogni applicazione di un host è individuata da un indirizzo univoco all’interno del host (porta). Funzionamento di TCP/IP • Quando un processo in un host A vuole trasmettere un messaggio a un processo in un host B deve: • consegnare il messaggio al livello TCP indicando l’host destinatario (B) e la porta del processo destinatario • TCP aggiunge info di controllo al messaggio (lo può anche spezzettare) e lo invia al livello IP. Il livello IP aggiunge informazioni di controllo al messaggio e lo invia al livello di accesso alla rete • il livello di accesso alla rete aggiunge un’ulteriore intestazione al messaggio e finalmente lo invia al livello fisico che lo spedirà. Indirizzi Internet • Il protocollo IP fornisce uno schema di indirizzamento universale. • indirizzi a 32 bit, di solito rappresentati come successione di 4 numeri decimali separati da punti: X.Y.Z.W, con X,Y,Z,W compresi tra 0 e 255. • • Es.: 66.102.11.104 • La versione attuale del protocollo IP non è più sufficiente: si è ormai vicini alla saturazione. Nuovo protocollo: IPv6, indirizzi a 128 bit, presenza di un supporto per audio e video,... Esiste un’organizzazione che assegna univocamente gli indirizzi IP chiamata IANA (Internet Assigned Number Authority) Indirizzi Internet Simbolici • Gli indirizzi numerici IP sono machine-oriented e difficilmente memorizzabili dall’uomo. • soluzione: associare ad ogni indirizzo numerico un indirizzo simbolico mediante un sistema denominato DNS (Domain name system). Es. www.google.com • I DNS eseguono la conversione degli indirizzi in maniera totalmente trasparente all’utente. Gli indirizzi simbolici sono suddivisi in domini e sottodomini. • Es. Considerate www.google.com • • • .com indica il dominio di primo livello google.com il dominio di secondo livello www.google.com individua il calcolatore nel sottodominio Affidabilità di TCP/IP • Protocolli orientati alla connessione (connection-oriented) • TCP • Protocolli non orientati alla connessione (connectionless) • IP, UDP (User Datagram Protocol) Il World Wide Web • L’architettura client-server è alla base di quasi tutti gli applicativi di Internet. • Il WWW (World Wide Web) è una tipica applicazione distribuita client-server composta da: • • Client, ovvero i browser (navigatori) Internet: e.g. Safari, Netscape, Internet Explorer,... • i Web server (Apache, Internet Information Server, ...) Client e server comunicano mediante il protocollo HTTP (HyperText Transfer Protocol) HTTP • il protocollo HTTP è utilizzato per condividere informazione sulla rete (pagine Web, documenti multimediali, etc.) • • Esempio d’uso: • Il server riceve la richiesta da parte del browser, reperisce l’informazione nel suo disco locale e la spedisce al cliente insieme ad alcune informazioni di controllo (e.g. codice d’errore, tipo di documento, lunghezza del documento, tipo di web server,...) • è un protocollo stateless: non mantiene la storia delle richieste ricevute. Il cliente (browser) richiede un’informazione indicando un indirizzo (Es.: http://polygen.org/web/Ghezzi.645.0.html) e genera un messaggio di tipo GET contenente indirizzo ed altre informazioni ausiliarie da inviare al server (e.g. versione del protocollo, tipo di browser, etc.). Altri servizi di rete • altri servizi Internet sono implementati mediante applicazioni client server • TELNET, permette di impiegare il proprio calcolatore come terminale di un calcolatore (protocollo SSH: versione di telnet sicura) • posta elettronica (SMTP - Simple Mail Transfer Protocol, POP3, IMAP) • trasferimento file (FTP - File Transfer Protocol, SFTP - Secure File transfer Protocol,...) • Utilità di rete • • • ping traceroute ... • Struttura del sistema email è gestito mediante un protocollo client-server. • Il programma client (e.g. Eudora, Outlook) si connette al mail server del mittente ed invia il messaggio mediante protocollo SMTP. • Sempre mediante SMTP il mail server del mittente invia il messaggio al mail server del destinatario. • L’utente destinatario scarica il messaggio dal server utilizzando uno dei seguenti protocolli • • Post Office Protocol 3 (POP3) Internet Message Access System (IMAP) Uniform Resource Locator • Uniform Resource Locator (URL) permette di identificare in modo univoco la risorsa e il metodo di accesso alla risorsa sulla rete. • In generale, protocollo://host:portaTCP/risorsa Applicazioni su più livelli • Un URL può individuare non solo dati ma anche programmi da dover eseguire in maniera remota. • In questo caso il browser richiede l’esecuzione del programma al server web che a sua volta delega il compito al programma vero e proprio (back-end). Si tratta di un’architettura su 3 livelli (client, server, back-end). Il sottosistema LA è gestito dal back-end. • È un sistema a deleghe successive: il server svolge anche un ruolo di client verso il back-end. • La richiesta del client può contenere anche una lista di parametri sui quali eseguire il programma. Essi vengono specificati mediante la standard Common Gateway Interface (CGI). Applicazioni su più livelli • Nelle applicazioni distribuite molto complesse possiamo avere una struttura su 4 livelli. la quale prevede un’applicazione (DBMS - Data Base Management System) per l’implementazione del sottosistema di gestione dei dati connessa al Back-end. • Browser <-> Web Server <-> Back-end <-> DBMS Sicurezza • Tecniche per filtrare il traffico di rete che operano a livello IP (sui router) • • Tecniche di sicurezza a livello TCP • • • packet filtering permettono di definire limitazioni nell’accesso ai servizi internet Virtual Private Network (VPN) Esistono calcolatori destinati a proteggere reti private da eventuali intrusioni (FireWall) • Spamming, virus, Deny of service attacks, mail bombing,... Sicurezza • Ipotizziamo che un’entità A si metta in comunicazione con un’entità B. I requisiti di sicurezza che si devono garantire sono • Privatezza dei dati trasmessi (evitare che un entità C intercetti il flusso di dati) • Integrità dei dati e servizi richiesti (C potrebbe frapporsi tra A e B e manipolare l’informazione in transito) • • Identità dei partner (C potrebbe camuffarsi da A o B) non ripudiabilità degli impegni (A potrebbe negare di aver inviato dati a B o B potrebbe negare di avere ricevuto dati da A). Sicurezza • Per garantire i requisiti di sicurezza si utilizzano tecniche di crittografia: • A critta con una chiave il messaggio e lo invia a B, B riceve il messaggio e lo decritta con una chiave. • Crittografia a chiave simmetrica • Crittografia a chiave asimmetrica C. a Chiave simmetrica • Le entità A e B devono condividere la stessa chiave per codificare e decodificare il messaggio e lo stesso programma di crittografia. • Svantaggio: come trasferire la chiave in modo sicuro da A a B? • La tecnica a chiave simmetrica non fornisce le capacità per garantire l’integrità dei dati e nemmeno l’identità del mittente. C. a chiave asimmetrica • Non è necessario fornire un canale sicuro per il trasferimento delle chiavi. Transitano infatti sulla rete solo chiavi pubbliche. • È necessario verificare a chi corrisponde una determinata chiave pubblica. • Esistono Autorità di Certificazione che garantiscono l’identità del proprietario di una data chiave pubblica. • Problema: chi controlla i controllori? C. a chiave asimmetrica • Ogni entità dispone di una coppia di chiavi (SW: GnuPG, PGP): • • la chiave pubblica la chiave privata • A critta il messaggio M con la sua chiave privata (firma digitale) ottenendo il messaggio firmato M1 • A critta M1 con la chiave pubblica di B e ottiene il messaggio crittato M2 da spedire a B. • B usa la sua chiave privata per decodificare il messaggio e poi la chiave pubblica di A per verificarne l’autenticità (i.e. la firma). Motori di ricerca • Sono delle risorse per il recupero dell’informazione tipicamente accessibili dalla rete • Tipicamente i risultati ottenuti sono classificati secondo la loro rilevanza mediante qualche metrica. • Permettono di ricercare informazione in differenti ambienti (Web, newsgroups, basi di dati...) Motori di ricerca • Come funzionano? • Browsers automatizzati esplorano il web (Web Crawlers, Web Spider, Web Robots) alla ricerca di nuove pagine Web • Le nuove pagine Web vengono catalogate ed il loro contenuto è indicizzato rispetto a delle parole chiave (titolo, headings, metatags...) • L’utente interroga il motore di ricerca fornendo tipicamente delle parole chiave (query) ed altri criteri di ricerca (alcuni motori supportano operatori booleani AND,OR,NOT, etc.) Un esempio: Google ambienti di ricerca criteri di ricerca avanzati query Google: criteri di ricerca Query complesse Ricerca frase: “frase da cercare” Ricerca di una delle seguenti query: query1 OR query2 OR... OR queryn Ricerca negativa: -query Ricerca formato: filetype:tipo_file_da_cercare Ricerca in un sito o dominio: site:sito_o_dominio_in_cui_cercare Ricerca pagine simili: related: pagina Ricerca pagine che contengono link a una data pagina: related: pagina Ricerca nell’url: allinurl:argomento Ricerca nel titolo: allintitle:argomento I criteri di ricerca possono esere composti per creare query più complesse. S.O. di rete • Oltre ai tipici moduli per la gestione di processore, memoria, periferiche, file system, interprete comandi si aggiunge un modulo per la • gestione delle risorse di rete Modelli organizzativi • I modelli organizzativi monolitico e a strati non sono più applicabili. • Modelli Client-server • Modelli ibridi M. Client-server • Il nucleo del S.O. è di dimensioni minime, la gestione delle funzionalità affidate a processi serventi (printer server, memory server, file server,...) • i processi clienti possono usufruire di un servizio, inviando una richiesta ai processi serventi (scambio messaggi). • Il nucleo deve fornire le funzionalità necessarie per stabilire la comunicazione tra processi clienti e processi serventi • I processi condividono informazione solo attraverso il nucleo mediante lo scambio di messaggi • Sono S.O. di rete altamente portabili Vantaggi • indipendenza fisica tra processi server e client. • possibilità di specializzare l’interfaccia grafica dei client, lasciando invariati i processi serventi. • riduzione della manutenzione (le parti che potrebbero essere comuni a molti processi sono contenute in un unico processo server) Modelli ibridi • I S.O. Client-server permettono la comunicazione fra processi solo attraverso lo scambio messaggi. • Nei S.O. ibridi, i processi (chiamati thread) sono suddivisi in gruppi • • all’interno di uno stesso gruppo i thread possono scambiarsi informazione mediante l’uso di aree di memoria comuni. • gruppi di thread distinti comunicano mediante scambio messaggi Permettono un uso più efficiente della CPU Traduzione dei programmi in rete • In una rete ci possono essere calcolatori con diverse archittetture e diversi linguaggi macchina. • Problema: come eseguire un programma su diversi calcolatori della rete? • • Soluzione: • • • Tradurre il programma ad alto livello in un programma bytecode Dotare ogni calcolatore di un interprete per un linguaggio intermedio (bytecode) interpretare il programma bytecode sui differenti calcolatori Esempio: il linguaggio Java Gestione dei processi • Una rete di calcolatori può essere vista come una generalizzazione di un sistema multiprocessore. Si ha almeno un processore per ogni nodo. • Il gestore dei processi deve dunque • • gestire l’evoluzione di un singolo processo su ogni nodo definire come distribuire i vari processi da eseguire sui nodi a disposizione. • Ogni nodo ha installato un kernel per gestire l’esecuzione dei processi che gli vengono assegnati • Esiste un processo a livello globale (dispatcher) che distribuisce i processi da eseguire fra i vari nodi secondo un certo criterio. (Es.: bilanciare il carico) Gestione della memoria • La memoria è distribuita in maniera più o meno uniforme fra i vari nodi. • Per ragioni di efficienza si segue il principio di località: si tende a mantenere sullo stesso nodo il processo e la memoria che gli è stata assegnata. Gestione delle periferiche • Si assegna ad ogni periferica un nome univoco. • Si accede alle periferiche da ogni nodo mediante il loro nome. • Ogni periferica è gestita da un processo responsabile. File system distribuiti • • • Un S.O. che consente una gestione distribuita del file system deve: • integrare in modo organico i singoli file system dei calcolatori della rete • • risolvere i problemi dell’univocità dei nomi consentire un accesso efficiente anche ai file presenti su calcolatori remoti Generalmente si usa un modello client-server. Esempio il Network File System (NFS) di Unix Applicazioni come sistemi distribuiti • Un’applicazione è definita mediante 3 sottosistemi: interfaccia utente (IU), sottosistema di logica applicata (LA), sottosistema di gestione dei dati (GD) • In un’applicazione di rete i 3 sottosistemi possono risiedere su calcolatori distinti. • Gestione tipica: client-server • sul nodo client (che potrebbe essere anche un palmare o un telefono cellulare) potrebbe essere implementata solo l’interfaccia utente • Applicazione server e applicazione client si scambiano i dati mediante un protocollo di comunicazione. Applicazioni peer to peer • Utilizzate tipicamente per lo scambio di file o per la comunicazione sincrona • • Non esiste una gerarchia tra i calcolatori che partecipano alla rete Le applicazioni peer to peer integrano una componente SERVer con una componente cliENT, si parla di sistemi SERVENT. • • sistema di condivisione file in Windows Gnutella, Kazaa (file sharing P2P), .... Max fra n n numeri Input: un naturale n e n naturali distinti Output: il massimo fra gli n naturali 1. 2. 3. 4. Leggi n i!0 max ! 0 mentre (i<n) fai { 4.1 leggi x 4.2 se (x>max) allora max ! x 4.3 i ! i+1 } 5. stampa max Somma di n numeri Input: un naturale n e n naturali Output: la somma degli n naturali 1. leggi n 2. sum ! 0 3. mentre (n>0)fai { 3.1 leggi x 3.2 sum ! sum + x 3.3 n ! n-1 } 4. stampa sum Esercizio Calcolare la media aritmetica di n naturali Media = (X1+X2+X3+... +Xn) n Sottoprogrammi • Per calcolare la media aritmetica fra n naturali sarebbe comodo riutilizzare il codice per la somma di di naturali. • I sottoprogrammi permettono di scrivere codice • modulare • leggibile • riutilizzabile Sottoprogrammi (definizione) • In un sottoprogramma è necessario definire quali sono i parametri di input e i parametri di output (definizione dell’interfaccia) • Tali parametri sono chiamati parametri formali. Sottoprogramma <nome sottoprg> (in: x1, x2,... xn; out: y1,y2,... ym) Blocco Esempio sottoprogramma somma (in:n; out: sum) { 1. sum ! 0 2. mentre (n>0)fai { 2.1 leggi x 2.2 sum ! sum + x 2.3 n ! n-1 } } Sottoprogrammi (chiamata) • Un sottoprogramma per essere eseguito deve essere “chiamato” da un’altro programma che lo utilizza esplicitando la lista di parametri di input e output (parametri attuali). • i nomi dei parametri formali e attuali possono essere distinti. Al momento della chiamata vengono messi in corrispondenza in base all’ordine in cui sono stati dichiarati. nomesottoprg(in:a1,...,an; out:b1,...,bm) nomesottoprg(in: a1, an; out: b1,..,bm) Media aritmetica Start 1. 2. 3. 4. leggi n1 somma(in:n1,out: sum1) media ! sum1/n1 stampa media Leggi n1 somma(in:n1;out: sum1) media ! sum1/n1 Stampa media Stop Media aritmetica Start Leggi n1 1. 2. 3. 4. 5. 6. 7. 8. leggi n1 somma(in:n1;out: sum1) media ! sum1/n1 stampa media n2 ! 5 somma(in:n2;out: sum2) media ! sum2/n2 stampa media somma(in:n1;out: sum1) media ! sum1/n1 Stampa media n2!5 somma(in:n2;out: sum2) media ! sum2/n2 Stampa media Stop Media aritmetica Leggi n1 somma(in:n1;out: sum1) media ! sum1/n1 sottoprogramma somma (in:n; out: sum) { 1. sum ! 0 2. mentre (n>0)fai { 2.1 leggi x 2.2 sum ! sum + x 2.3 n ! n-1 } } Stampa media n2!5 somma(in:n2;out: sum2) media ! sum2/n2 Stampa media sottoprogramma somma (in:n; out: sum) { 1. sum ! 0 2. mentre (n>0)fai { 2.1 leggi x 2.2 sum ! sum + x 2.3 n ! n-1 } } La ricorsione • La ricorsione è una tecnica di programmazione attraverso la quale un sottoprogramma chiama se stesso. • Un esempio è il calcolo del fattoriale di un numero naturale. Il fattoriale di 0 è 1. Il fattoriale di n, numero naturale maggiore di 0, è dato dal prodotto di tutti i numeri interi compresi tra 1 ed n. • Es: 0!=1, 1!=1, 5!=5*4*3*2*1=120 Fattoriale (versione iterativa) Input: numero naturale n Output: fattoriale di n (n!) sottoprogramma fattoriale(in:n; out: fatt) { fatt ! 1 mentre (n>0) fai { fatt ! fatt*n n ! n-1 } } Fattoriale (versione ricorsiva) fattoriale(n)= { 1 se n=0 n*fattoriale(n-1) se n>0 Fattoriale (versione ricorsiva) sottoprogramma fattoriale(in:n; out: fatt) 1. se (n=0)allora 1.1 fatt ! 1 altrimenti { 1.2 fattoriale(in:(n-1); out: fatt1) 1.3 fatt ! n*fatt1 } Fibonacci Immaginiamo di chiudere una coppia di conigli in un recinto. Sappiamo che ogni coppia di conigli: a) inizia a generare dal secondo mese d’età b) genera una coppia di conigli al mese c) non muore mai. Quanti conigli ci saranno nel recinto dopo un anno ? Fibonacci soluzione ricorsiva fib(0) = 1 fib(1) = 1 fib(n) = fib(n-1)+fib(n-2) se n>1 dove fib(k)=”numero di coppie di conigli al mese k” L’algoritmo sottoprogramma Fibonacci(in: n; out: num_conigli) { 1. se ((n=0) o (n=1)) allora 1.1 num_conigli ! 1 altrimenti { 1.2 Fibonacci(in:n-1;out:num_conigli1) 1.3 Fibonacci(in:n-2;out:num_conigli2) 1.4 num_conigli ! num_conigli1+num_conigli2 } } Fibonacci Soluzione iterativa sottoprogramma Fibonacci_it(in:n;out:num_conigli) { 1. num_conigli_prec ! 1 2. num_conigli ! 1 3. mentre (n>1) fai { 3.1 aux ! num_conigli 3.2 num_conigli ! num_conigli + num_conigli_prec 3.3 num_conigli_prec ! aux 3.4 n ! n-1 } } ... e dopo un anno ci saranno 233 coppie di conigli La torre di Hanoi ll fine del gioco è trasferire i dischi dal piolo A al piolo C. Regole: •! muovere un disco alla volta !• mai mettere un disco più largo su uno più stretto. Soluzione ricorsiva: •! trasferisci N-1 dischi da A a B. !• muovi il disco più largo da A a C. !• trasferisci N-1 dischi da B a C La torre di Hanoi sottoprogramma Hanoi(in:n,A,B,C) { 1. se (n=1) allora 1.1 MuoviDisco(in: A,C) altrimenti { 1.2 Hanoi(in: (n-1), A,C,B) 1.3 MuoviDisco(in:A,C) 1.4 Hanoi(in: (n-1),B,A§,C) } } sottoprogramma MuoviDisco(in:A,B){ 1. stampa “Muovi il disco da A a B” } Vettori (array) • I vettori sono una struttura dati che permette di memorizzare sequenze di dati omogenei (sequenze di interi, di valori booleani,...) • I vettori sono caratterizzati da • • dimensione tipo • • Es. v[10] • notazione: v[i]=”i-esimo elemento del vettore v” v= 3 5 7 9 0 0 2 1 3 4 0 1 2 3 4 5 6 7 8 9 I singoli elementi di un vettore possono essere riferiti mediante un indice. Esercizi • Memorizzare n valori interi in un vettore di dimensione n • Stampare i valori contenuti in un vettore di dimensione n • Cercare un elemento X all’interno di un vettore di n elementi (ricerca lineare, binaria) Vettori (array) • Un vettore è una struttura dati che permette di memorizzare sequenze di dati omogeneii (sequenze di interi, di valori booleani,...) • I vettori sono caratterizzati da • • dimensione tipo 3 5 7 9 0 0 2 1 3 4 • • Es. v[10] • notazione: v[i]=”i-esimo elemento del vettore v” v= 0 1 2 3 4 5 6 7 8 9 I singoli elementi di un vettore possono essere riferiti mediante un indice. Operazioni sui vettori • Possiamo scrivere e leggere una singola cella di un vettore. Esempi di istruzioni di input/output su vettori - leggi v[i] - scrivi v[i] Esempi di istruzioni di assegnamento su vettori - v[i] ! exp - X ! v[i] - w[j] ! v[i] Alcuni esercizi sui vettori Problema: Dato un vettore di interi w di dimensione m, calcolare l’elemento minimo di w. sottoprogramma minvet(in:w,m;out: min) { 1. min!w[0] 2. i!1 3. mentre (i<m) fai{ 3.1. se w[i]<min allora 3.1.1. min ! w[i] 3.2 i!i+1 } } Problema: dati due vettori di interi v1 e v2 di dimensioni n1 e n2, verificare se v1 e v2 sono uguali. sottoprogramma vett=(in:v1,n1,v2,n2: out: uguali) { 1. I!0 2. se (n1<>n2) allora 2.1 uguali!falso altrimenti { 2.2 uguali!vero 2.3 i!0 2.4 mentre (i<n1) e (uguali=vero) fai{ 2.4.1 se v1[i]<>v2[i] allora 2.4.1.1 uguali!falso 2.4.2 i!i+1 } } } Problema: Dato un vettore di caratteri v di dimensione n, verificare se la parola o frase contenuta è palindroma. Esempi di palindrome: “Onorarono” “Avida di vita, desiai ogni amore vero, ma ingoiai sedativi da diva” "O mordo tua nuora o aro un autodromo" “Was it a cat I saw?” (L. Carroll - Alice; citato da Titti quando dice "Mi è semblato di vedele un gatto") Soluzione sottoprogramma palindroma?(in:v,n:out:pal) { 1. I!0 2. J!n-1 3. pal!vero 4. mentre (I<n/2) e (pal=vero) fai{ 4.1. se (v[I]<>v[J]) allora 4.1.2. pal!falso 4.2. I!I+1 4.3. J!J-1 } } Algoritmi di ricerca • Problema: dato un vettore v di dimensione n e un elemento X, determinare se X è contenuto in v. • Soluzioni possibili: • ricerca lineare • ricerca binaria Ricerca lineare • Soluzione: scorrere tutto il vettore v da posizione 0 a posizione (n-1) e controllare ogni singolo elemento. Fermarsi nel caso in cui v[i]=X, per qualche i=1,...,n. L’algoritmo sottoprogramma ricerca-lineare (in:v,n,x;out: trovato) { trovato ! falso i !0 mentre ((i<n) and (not trovato)) fai { se (v[i]=X) allora trovato ! vero i ! i+1 } } • Nel caso pessimo (elemento non trovato): dovrò scorrere tutta la lista di elementi Indovina chi? Gioco: Un giocatore A sceglie una persona in un insieme di 80 persone. Un giocatore B deve indovinare di chi si tratta ponendo ad A al massimo 7 domande. Ricerca binaria • Nel caso in cui il vettore fosse ordinato possiamo utilizzare un metodo piu’ efficiente per ricercare un elemento in un vettore. • Metodo • • Determino il valore v[m] che sta nella posizione centrale del vettore • • Se v[m]=x, allora ho trovato l’elemento cercato, altrimenti... Se x<v[m], cerco l’elemento nella prima metà del vettore, altrimenti lo cerco nella seconda metà. Il metodo mi permette sempre di scartare metà degli elementi senza doverli leggere. Esempio Cerco il valore 7 (di volta in volta calcolo l’estremo inferiore di (n-1)/2) 3 4 5 7 9 10 12 13 14 24 7<9 3 4 5 7 7>4 5 7 7>5 7 L’algoritmo sottoprogramma RicercaBinaria(in:v,n,x;out:trovato) { trovato ! falso max ! n-1 min ! 0 mentre (min <= max) and (not trovato) fai { m ! (max+min)/2 se (x = v[m]) allora trovato ! vero altrimenti se (x < v[m]) allora max ! m-1 altrimenti min ! m+1 } } Ordinamento • Problema dato un vettore v di lunghezza n contenente una sequenza disordinata di interi, ordinare la sequenza in senso crescente (o decrescente). • Esempio input 3 5 7 9 0 0 2 1 3 4 output 0 0 1 2 3 3 4 5 7 9 Bubble sort • È l’algoritmo di ordinamento più vecchio e anche il più lento! • Metodo: si scandisce il vettore confrontando elementi adiacenti, nel caso sia necessario si scambiano gli elementi. L’algoritmo ripete tale operazione finché non ci sono più posizioni da scambiare (vettore ordinato). • Durante l’esecuzione dell’algoritmo gli elementi più grandi (piu’ piccoli, nel caso di ordinamento decrescente) tendono a spostarsi (come bolle!) verso la fine del vettore. Esempio Ordiniamo con bubble sort il vettore 3 2 0 1 2 0 1 3 0 1 2 3 2 3 0 1 0 2 1 3 0 1 2 3 2 0 3 1 0 1 2 3 2 0 1 3 3 2 0 1 0 1 2 3 L’algoritmo sottoprogramma bubblesort(in:v,n;out:v) { i !0 mentre (i < n-1) fai { j !0 mentre (j < n-i-1) fai { se (v[j+1] > v[j]) allora scambia(in:v[j],v[j+1];out:v[j],v[j+1]); j ! j+1 } i ! i+1 } } Merge sort • È un algoritmo di ordinamento ricorsivo basato sull’approccio “divide and conquer” • • • • “dividi” il problema in sottoproblemi “conquista” i sottoproblemi, risolvendoli ricorsivamente combina le soluzioni dei sottoproblemi per ottenere la soluzione del problema originale Algoritmo di merge sort • DIVIDE: dividi il vettore di n elementi in due sottovettori di n/2 elementi • • CONQUER: ordina i due sottovettori COMBINE: fondi assieme i due sottovettori ordinati in un unico vettore ordinato Esempio 3 2 0 1 3 2 3 2 0 1 0 1 Merge 2 3 0 1 Merge 0 1 2 3 Merge • Problema: fondere assieme due sottovettori (v[p...q], v[q+1..r]) ordinati ottenendo un unico vettore ordinato v. p q r 3 7 8 1 5 1 3 5 7 8 Merge - l’algoritmo sottoprogramma merge(in:v,p,q,r: out v) { i !p j ! q+1 k !0 mentre (i<=q) and (j<=r) fai se v[i]<=v[j] allora { aux[k] ! v[i] k ! k+1 i ! i+1 } altrimenti { aux[k] ! v[j] k ! k+1 j ! j+1 } mentre (i<=q) fai { aux[k] ! v[i] k ! k+1 i ! i+1 } mentre (j<=r) fai { aux[k] ! v[j] k ! k+1 j ! j+1 } copia(in aux; out v) } Merge sort l’algoritmo sottoprogramma mergesort(in: v,p,r;out: v) se (p<r) allora { q ! (p+r/2) mergesort(in: v,p,q; out: v) mergesort(in: v,q+1,r; out v) merge(in:v,p,q,r) } ipertesti • Obiettivo: strutturare l’informazione per renderla accessibile a esseri umani. • rappresentazione sequenziale (es. stampa) • rappresentazione non sequenziale (struttura fisica del documento differisce dalla struttura logica) (es: enciclopedia) Ipertesto • si definisce ipertesto un documento la cui struttura di consultazione è non lineare • ogni parte del documento (chiamata nodo) può contenere dei punti di aggancio (anchor point) che collegano altre parti del documento (chiamati nodi target) mediante collegamenti ipertestuali (hyperlink) Es. struttura sequenziale • Cap. 2: Paolo Conte nasce il 6 gennaio 1937 e già da adolescente coltiva la passione per il jazz classico americano [...] • Cap. 5: • Cap. 13: Paolo Conte ha scritto Razmataz [...] Razmataz è un album del 2000 che contiene [...] Es. ipertesto Paolo Conte nasce il 6 gennaio 1937 e già da adolescente coltiva la passione per il jazz classico americano [...] Paolo Conte ha scritto Razmataz [...] Razmataz è un album del 2000 che contiene [...] Linguaggio per ipertesti • Un linguaggio per descrivere gli ipertesti è l’HyperText Markup Language (HTML) • • Non è il solo (VRML,XML,...) l’HTML è un linguaggio di formattazione e permette di • formattare del testo secondo certi criteri mediante dei marcatori (tag) • fare riferimento ad altri testi o contenuti multimediali mediante collegamenti (hyperlink o link) HTML e sua evoluzione • HTML iniziale • basato su un sistema di marcatori (tag) • permetteva di gestire la struttura di un documento • la presentazione del documento era rozzamente gestita • HTML 3.2 (e successivamente HTML 4.01) • Aggiunti Tag per la presentazioneTags (e.g., font size o color) • Problemi di compatibilità fra browsers • Cascading Style Sheets (CSS) • Obiettivo: Separare la presentazione dalla stuttura del doc. • XHTML • HTML di nuova generazione • Include nuovi tags • Impone regole più strette nella stesura dei documenti ipertestuali Tag • Sono dei marcatori che servono a • indicare l’aspetto grafico del testo (tipo di font e stile del carattere, allineamento dei paragrafi,...) • indicare dove reperire altra informazione multimediale e/o testuale • far interagire l’utente con la pagina stessa (es. moduli on-line) Tag - sintassi e semantica • un tag t si usa in questo modo <t> testo a cui si riferisce il tag t </t> L’effetto di un tag t è di applicare il comando associato al tag t al “testo a cui si riferisce il tag t” I tag senza "contenuto" (e.g. <t></t>) si indicano in HTML con il solo tag iniziale <t>; in XHTML con il tag <t /> Tag di base • HTML • HEAD • TITLE • BODY Tag HTML • Permette di delimitare l’inizio e la fine di un documento HTML. • Un documento HTML è racchiuso tra i tag <HTML> e </HTML> Tag HEAD • Permette di definire l’intestazione del documento (titolo, informazioni per il browser ...) • Deve essere posto immediatamente dopo il tag <html> <html> <head> ... </head> ... </html> Tag TITLE • Permette di definire il titolo della pagina web, deve essere inclusonell’intestazione <head> <title> ... </title> ... </head> <title> Demis Ballis’ Home Page </title> Tag BODY • Contiene il corpo del documento html (testo, immagini, suoni,...) • È posto dopo il tag </head> <head> ... </head> <body> Questa è una pagina HTML </body> Struttura di un documento HTML Intestazione Corpo <html> <head> <title> Pagina di prova </title> </head> <body> Questo è il contenuto della pagina! </body> </html> HTML o XHTML? XHTML 1.0 Strict <?xml version="1.0"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http:// www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <HMTL> ... </HTML> XHTML 1.0 Transitional <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <HTML> ... </HTML> HTML 4.01 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 TRANSITIONAL//EN"> <HTML> ... </HTML> Esempio Attributi dei tag • Ad alcuni tag sono associati degli attributi che specificano delle proprietà inerenti ai tag. • Se si vuole impostare l’attributo A1 del tag t al valore 15 e l’attributo A2 al valore “pippo” si dovrà scrivere <t a1=”15” a2=”pippo”> ... </t> Attributi di BODY • BGCOLOR fissa il colore di sfondo (sconsigliato in XHTML) <body BGCOLOR=”red”>... </body> oppure <body BGCOLOR=”#FF0000”>... </body> Attributi di BODY • BACKGROUND fissa un’immagine di sfondo (sconsigliato in XHTML) <body> BACKGROUND=”sfondo.gif”>... </body> Attributi di BODY • TEXT imposta un colore per il testo (sconsigliato in XHTML) <body TEXT=”#0000FF”>... </body> Attributi di BODY • VLINK, ALINK,LINK impostano rispettivamente i colori dei collegamenti visitati, cliccati ma non ancora visitati e non ancora cliccati. (sconsigliato in XHTML) <body LINK=”#FFFFFF”>... </body> Formattazione del testo • Alcuni tag per formattare il testo • <H1>, <H2>,... <H6> • <FONT> • <U>, <I>, <B>, <STRIKE> I Tag <H1>... <H6> • Definisce lo stile dei titoli inclusi nel documento HTML. <H1> Sezione 1 </H1> blahblah blahblah <H2> Sottosezione 1.1 </H2> blahblah blahblah Tag <FONT> • Serve per definire gli attributi del testo al quale è riferito (carattere, dimensione, ...) • Alcuni Attributi di FONT • • • SIZE (dimensione del caratte, da 1 a 7) FACE (tipo di carattere) COLOR (colore del carattere) <FONT COLOR=”RED” SIZE=”2” FACE=”Arial”> questo è un testo di colore rosso, dimensione 2 e font Arial! </FONT> I Tag <U>,<B>,<I>,<STRIKE> • • • • <U> testo sottolineato </U> <B> testo in grassetto </B> (sconsigliato in XHTML) <I> testo in corsivo </I> (sconsigliato in XHTML) <STRIKE> testo barrato </STRIKE> I Tag <BLOCKQUOTE>,<CITE> • • BLOCKQUOTE permette di definire delle citazioni CITE permette di definire la fonte della citazione <BLOCKQUOTE> PENSATORE:! L'ippopotamo è un animale completamente inutile nel creato. LA FEMMINA DELL' IPPOPOTAMO: Lo dice lei!! </BLOCKQUOTE> <CITE> Da Tragedie in due battute, A. Campanile </CITE> I Tag <EM>,<STRONG> • • EM mette in evidenza il testo STRONG marca il testo <EM> evidenzia il testo </EM> <STRONG> marca il testo </STRONG> ANDARE A CAPO • tutto il testo scritto in un documento HTML è rappresentato in sequenza. <BODY> IL SIGNOR TALE: "Ciao, carissimo. Dove vai?". IL SIGNOR TALALTRO: "All'Arcivescovado. E tu?". IL SIGNOR TALE: "Dall'Arcivescovengo". </BODY> IL SIGNOR TALE: "Ciao, carissimo. Dove vai?". IL SIGNOR TALALTRO: "All'Arcivescovado. E tu?". IL SIGNOR TALE: "Dall'Arcivescovengo". IL TAG <BR> • si usa per andare a capo. • <br /> in XHTML <BODY> IL SIGNOR TALE: "Ciao, carissimo. Dove vai?". <BR> IL SIGNOR TALALTRO: "All'Arcivescovado. E tu?". <BR> IL SIGNOR TALE: "Dall'Arcivescovengo". <BR> </BODY> IL SIGNOR TALE: "Ciao, carissimo. Dove vai?". IL SIGNOR TALALTRO: "All'Arcivescovado. E tu?". IL SIGNOR TALE: "Dall'Arcivescovengo". Paragrafi e giustificazione • il tag P definisce un nuovo paragrafo • il tag DIV allinea il testo • il tag CENTER centra il testo IL TAG <P> • il tag P definisce un nuovo paragrafo. • È dotato dell’attributo ALIGN per allineare il testo a destra o a sinistra. ALIGN=”LEFT” ALIGN=”RIGHT” ALIGN=”CENTER” Some say the world will end in fire; Some say in ice. From what I've tasted of desire I hold with those who favor fire. Some say the world will end in fire; Some say in ice. From what I've tasted of desire I hold with those who favor fire. Some say the world will end in fire; Some say in ice. From what I've tasted of desire I hold with those who favor fire. IL TAG <DIV> • il tag DIV allinea il testo. • È dotato dell’attributo ALIGN per allineare il testo a destra o a sinistra. ALIGN=”LEFT” ALIGN=”RIGHT” ALIGN=”JUSTIFY” ALIGN=”CENTER” <DIV ALIGN=”RIGHT”> blablablabla </DIV> IL TAG <P> • il tag CENTER permette di allineare al centro un oggetto. <CENTER> oggetto da centrare </CENTER> ELENCHI • • • • il tag LI definisce un elemento in un elenco il tag OL definisce un elenco numerato il tag UL definisce un elenco non numerato Es. Elenco non numerato • • • elemento a elemento b Es. Elenco numerato 1. elemento a 2. elemento b IL TAG <OL> • il tag OL definisce un elenco numerato <OL> <LI> elemento a </LI> <LI> elemento b </LI> <LI> elemento c </LI> </OL> 1. elemento a 2. elemento b 3. elemento c Attributi di <OL> • Il tag OL ha un attributo TYPE che permette di definire il tipo di enumerazione • TYPE=”a” le etichette sono lettere minuscole (a,b,c,...) • TYPE=”A” le etichette sono lettere maiuscole (A,B,C,...) • TYPE=”i” le etichette sono numeri romani minuscoli (i,ii,iii,...) • TYPE=”I” le etichette sono numeri romani maiuscoli (I,II,III,...) IL TAG <UL> • il tag UL definisce un elenco non numerato <UL> <LI> elemento a </LI> <LI> elemento b </LI> <LI> elemento c </LI> </UL> • elemento a • elemento b • elemento c Attributi di <UL> • Il tag UL ha un attributo TYPE che permette di definire il tipo di etichette • • • TYPE=”disc” le etichette sono pallini pieni TYPE=”circle” le etichette sono cerchi TYPE=”square” le etichette sono quadrati pieni Le immagini • Per inserire un’immagine si utilizza il tag IMG • <img lista attributi /> in XHTML • Gli attributi più importanti di IMG sono • SRC: indica il niome dell’immagine da caricare • ALT: indica la didascalia • WIDTH, HEIGHT: specificano le dimensioni (in pixel o in percentuale) • ALIGN: indica l’allineamento => TOP,BOTTOM, MIDDLE,LEFT, RIGHT Le immagini • Per inserire un’immagine si utilizza il tag IMG • <img lista attributi /> in XHTML • Gli attributi più importanti di IMG sono • SRC: indica il niome dell’immagine da caricare • ALT: indica la didascalia • WIDTH, HEIGHT: specificano le dimensioni (in pixel o in percentuale) • ALIGN: indica l’allineamento => TOP,BOTTOM, MIDDLE,LEFT, RIGHT Collegamenti • Possono essere interni o esterni al documento HTML • Vengono definiti mediante il tag A. • Gli attributi più importanti sono: • HREF: indica un riferimento • TITLE: indica il titolo del collegamento • NAME: marca un riferimento interno Esempi di collegamenti Per visitare il sito dell’università di Udine clicca <A HREF=”http://web.uniud.it”> qui </a> <A NAME=”rif”> questo e’ un riferimento interno di nome rif </a> Nel documento, per accedere alla parte marcata dal collegamento interno rif clicca <A HREF=”#rif”> qui </a> Tabelle • Le tabelle si definiscono mediante il tag TABLE • Le singole righe si definiscono mediante il tag TR • le celle di ogni riga si definiscono mediante il tag TD Esempio Tabella <TABLE> <TR> <TD> <TD> </TR> <TR> <TD> <TD> </TR> </TABLE> pippo </TD> 25/30 </TD> pluto </TD> 30/30 </TD> pippo 25/30 pluto 30/30 L’attributo BORDER • è un attributo del tag TABLE. Permette di creare una cornice attorno alla tabella. Assume valori interi positivi => più grande è il valore assunto, più spessa è la cornice. <TABLE BORDER=2> <TR> <TD> pippo </TD> <TD> 25/30 </TD> </TR> <TR> <TD> pluto </TD> <TD> 30/30 </TD> </TR> </TABLE> Linguaggio Java: sintassi Gli elementi costitutivi di un programma Java sono chiamati token I token sono suddivisi in 5 categorie: • • • • • parole chiave letterali identificatori operatori separatori N.B. oltre ai token un programma Java può includere spazi e commenti che il compilatore ignora. Parole chiave Le parole chiave hanno un uso e un significato speciale in Java. abstract boolean break byte case default do double else if implements import private protected this throw catch char class const goto extends final finally float for package instanceof int interface long native new public return short static strictfp super switch throws transient try void volatile while continue synchronized Letterali I letterali si dividono in • • • • • • numeri interi (es: 679) numeri decimali o in virgola mobile (es: 123.789) valori booleani (true e false) caratteri UNICODE (es: ‘a’) stringhe (es: “pippo”) il riferimento nullo null Identificatori Gli identificatori rappresentano nomi che possono essere assegnati a variabili, metodi, classi, ecc. Un identificatore è composto esclusivamente da lettere, numeri e caratteri _ e $ e deve cominciare con una lettera, con _ , oppure con $. , Un identificatore non può essere una parola chiave, un letterale booleano, un letterale nullo. Identificatori validi: PIPPO, H2So4, $bank, nome_var Identificatori illegali: 2PIPPO, nome-var,int, true N.B. Java distingue fra lettere maiuscole e minuscole pertanto i due identificatori Pippo e PIPPO sono da considerarsi distinti. Operatori Gli operatori indicano un tipo di calcolo da eseguire su uno o piú dati, detti operandi, che possono essere letterali, variabili o risultati di valutazioni di espressioni = > < ! ? : ~ == <= >= != && || ++ -- + - * / & | ^ += -= *= /= &= |= ^= Separatori I separatori sono i “segni di punteggiatura” del linguaggio ( ) { } [ ] ; , . Commenti /* questo e un commento */ tutti i caratteri da /* a */ sono ignorati /** questo è un commento */ come /* */ ed inoltre permette di creare automaticamente la documentazione Javadoc // questo è un commento tutti i caratteri da // fino a fine linea sono ignorati Esempio /** Esempio di classe */ public class VotiEsame { private int voti[]; // variabile di tipo vettore di interi public VotiEsame(int n) { voti = new int[n]; // inizializza un vettore di lunghezza n } // genera un vettore contenente interi pseudo-casuali compresi tra 15 e 31 public void generavoti() { int i=0; Random r=new Random(); for (i=0;i<voti.length;i++) voti[i]=15+r.nextInt(16); System.out.println("Vettore generato!"); } // stampa vettore public void stampavoti() { int i=0; for (i=0;i<voti.length;i++) System.out.println("Elemento in posizione "+i+": "+voti[i]); } Esempio /** Esempio di classe */ public class VotiEsame { private int voti[]; // variabile di tipo vettore di interi 5 commenti public VotiEsame(int n) { voti = new int[n]; /* inizializza un vettore di lunghezza n*/ } // genera un vettore contenente interi pseudo-casuali compresi tra 15 e 31 public void generavoti() { int i=0; Random r=new Random(); for (i=0;i<voti.length;i++) voti[i]=15+r.nextInt(16); System.out.println("Vettore generato!"); } // stampa vettore public void stampavoti() { int i=0; for (i=0;i<voti.length;i++) System.out.println("Elemento in posizione "+i+": "+voti[i]); } Esempio /** Esempio di classe */ public class VotiEsame { private int voti[]; // variabile di tipo vettore di interi 17 parole chiave public VotiEsame(int n) { voti = new int[n]; /* inizializza un vettore di lunghezza n*/ } // genera un vettore contenente interi pseudo-casuali compresi tra 15 e 31 public void generavoti() { int i=0; Random r=new Random(); for (i=0;i<voti.length;i++) voti[i]=15+r.nextInt(16); System.out.println("Vettore generato!"); } // stampa vettore public void stampavoti() { int i=0; for (i=0;i<voti.length;i++) System.out.println("Elemento in posizione "+i+": "+voti[i]); } Esempio /** Esempio di classe */ public class VotiEsame { private int voti[]; // variabile di tipo vettore di interi 9 letterali public VotiEsame(int n) { voti = new int[n]; /* inizializza un vettore di lunghezza n*/ } // genera un vettore contenente interi pseudo-casuali compresi tra 15 e 31 public void generavoti() { int i=0; Random r=new Random(); for (i=0;i<voti.length;i++) voti[i]=15+r.nextInt(16); System.out.println("Vettore generato!"); } // stampa vettore public void stampavoti() { int i=0; for (i=0;i<voti.length;i++) System.out.println("Elemento in posizione "+i+": "+voti[i]); } Esempio /** Esempio di classe */ public class VotiEsame { private int voti[]; // variabile di tipo vettore di interi 36 identificatori public VotiEsame(int n) { voti = new int[n]; /* inizializza un vettore di lunghezza n*/ } // genera un vettore contenente interi pseudo-casuali compresi tra 15 e 31 public void generavoti() { int i=0; Random r=new Random(); for (i=0;i<voti.length;i++) voti[i]=15+r.nextInt(16); System.out.println("Vettore generato!"); } // stampa vettore public void stampavoti() { int i=0; for (i=0;i<voti.length;i++) System.out.println("Elemento in posizione "+i+": "+voti[i]); } Esempio /** Esempio di classe */ public class VotiEsame { private int voti[]; // variabile di tipo vettore di interi 15 operatori public VotiEsame(int n) { voti = new int[n]; /* inizializza un vettore di lunghezza n*/ } // genera un vettore contenente interi pseudo-casuali compresi tra 15 e 31 public void generavoti() { int i=0; Random r=new Random(); for (i=0;i<voti.length;i++) voti[i]=15+r.nextInt(16); System.out.println("Vettore generato!"); } // stampa vettore public void stampavoti() { int i=0; for (i=0;i<voti.length;i++) System.out.println("Elemento in posizione "+i+": "+voti[i]); } Esempio /** Esempio di classe */ public class VotiEsame { private int voti[]; // variabile di tipo vettore di interi 52 separatori public VotiEsame(int n) { voti = new int[n]; /* inizializza un vettore di lunghezza n*/ } // genera un vettore contenente interi pseudo-casuali compresi tra 15 e 31 public void generavoti() { int i=0; Random r=new Random(); for (i=0;i<voti.length;i++) voti[i]=15+r.nextInt(16); System.out.println("Vettore generato!"); } // stampa vettore public void stampavoti() { int i=0; for (i=0;i<voti.length;i++) System.out.println("Elemento in posizione "+i+": "+voti[i]); } Tipi di dato in Java • Java è un linguaggio fortemente tipato in quanto ogni variabile ed ogni espressione hanno associato un tipo. • I tipi limitano l’insieme di valori che una variabile o un’espressione possono assumere. • Tipo di dato = (Supporto, Operazioni) • Tipi di dato primitivi e Tipi di dato astratti Tipi di dato primitivi • • il tipo booleano boolean (valori: true e false) • i tipi per i numeri decimali float (32 bit), double (64 bit) • il tipo carattere char i tipi per i numeri interi byte (8 bit), short (16 bit), int (32 bit), long (64 bit). Tipi di dato astratti • In Java sono anche chiamati tipi riferimento • I tipi riferimento sono classi, vettori, interfacce. Variabili • Una variabile è una locazione della memoria referenziabile mediante un identificatore. • Una variabile di un tipo primitivo può contenere solo valori del supporto di tale tipo. • Una variabile di tipo T, dove T è un tipo riferimento, può contenere un riferimento a qualunque istanza di T oppure il valore null. Dichiarazione di variabili • L’associazione di una variabile a un tipo ha luogo al momento della dichiarazione di tale variabile. <tipo> <identificatore>; oppure <tipo> <identificatore1>,..., <identificatoreN>; Esempi dichiarazioni int X, pippo; double radice; float r,c; String Codice_fiscale; Persona p1,p2,p3; Tipi primitivi Tipi riferimento Assegnamento (=) L’operatore di assegnamento (=) permette di memorizzare in una variabile un valore ottenuto dalla valutazione di una espressione. <identificatore> = <espressione>; • Una variabile per essere assegnata deve prima essere stata dichiarata; • È lecito combinare dichiarazioni con assegnamenti. La sintassi è la seguente: • <tipo> <identificatore> = <espressione>; • In generale, <identificatore> e <espressione> devono avere lo stesso tipo. Esempi di assegnamento String parola=”pippo”; dich. e int x,y; double d; dichiarazioni Persona p; p d x y x y z ass. combinati = new Persona(“mario”,”Rossi”,34,’M’); = 3.1459; = 1; =(x*5)+4; = parola; = 3.29; errori di assegnamento = 6; Conversioni di tipo • A volte è necessario assegnare espressioni di tipo T1 a variabili di tipo T2, con T1 e T2 tipi di dato distinti. È sempre possibile? • L’operazione di conversione di tipo è chiamata casting e può essere implicita o esplicita. Casting implicito • Il casting implicito è lecito quando non comporta nessuna perdita di precisione. int i=5; double j=3,1456; j = i; /* casting implicito lecito */ i = j; /* casting implicito illegale perdita di precisione */ Casting esplicito • nel casting esplicito il tipo in cui si vuole convertire una variabile deve essere fornito esplicitamente. • Può comportare perdita di precisione. int i = 65; char c; double j = 3,1456; i = (int) j; /* casting esplicito legale con perdita di precisione */ c = (char) i; /* assegna a c il codice UNICODE i */ j = (double) i; /* casting esplicito legale senza perdita di precisione */ Blocchi Il codice Java è diviso in blocchi delimitati da parentesi graffe aperte e chiuse. I blocchi possono essere annidati gli uni dentro gli altri. Public Class Esempio { // def. attributi private int x; private String s; // def. metodi public Esempio(int y, String s) { } // corpo del costruttore public void metodo() { // corpo del metodo } } Ambito delle variabili È possibile dichiarare ed usare variabili in ogni blocco del programma. L’ambito (o scope) in cui tali variabili possono essere utilizzate è limitato al blocco in cui sono state dichiarate e ai sottoblocchi eventualmente annidati. Le variabili dichiarate nel corpo di una classe definiscono gli attributi della classe. Le variabili dichiarate nel corpo di un metodo sono dette variabili locali, in quanto il loro ambito è ristretto al corpo del metodo. Le variabili locali vengono create al momento dell’esecuzione di un metodo e distrutte quando esso termina. Esempio Public Class Esempio { private int x=5; // def. metodi public Esempio(int y, String s) { char c=’B’; System.out.println(“valore di x: ”+x); System.out.println(“valore di c: ”+c); } public void metodo() { String s=”pippo”; System.out.println(“valore di s: “+s); System.out.println(“valore di c: ”+c); } } Esempio Public Class Esempio { private int x=5; // def. metodi public Esempio(int y, String s) { char c=’B’; System.out.println(“valore di x: ”+x); System.out.println(“valore di c: ”+c); } public void metodo() { Errore: la variabile c non è visibile in questo blocco! String s=”pippo”; System.out.println(“valore di s: “+pippo) System.out.println(“valore di c: ”+c); } } Ambito (cont.) Che succede se dichiaro variabili con lo stesso nome? Non è possibile dichiarare variabili con lo stesso nome all’interno dello stesso blocco. public metodo() { int i; char i; /* errore i è già definita! */ ... } È possibile dichiarare variabili con lo stesso nome all’interno di blocchi distinti anche se sono annidati. Ciò non crea alcun conflitto, in quanto la dichiarazione più interna nasconde le eventuali dichiarazioni più esterne. Esempio Che valore stampa l’esecuzione del metodo metodA()? E metodoB()? Public Class Esempio { private int x=5; public void metodoA() { char x=’A’; System.out.println(“valore di x: ”+x); } } public void metodoB() { System.out.println(“valore di x: ”+x); } Esempio Che valore stampa l’esecuzione del metodo metodA()? E metodoB()? Public Class Esempio { private int x=5; Stampa il carattere ‘A’ public void metodoA() { char x=’A’; System.out.println(“valore di x: ”+x); } } public void metodoB() { System.out.println(“valore di x: ”+x); } Stampa l’intero 5 Espressioni Un’espressione permette di calcolare un risultato applicando opportuni operatori a un certo numero di operandi, che possono essere variabili, letterali, valori di ritorno di metodi o altre espressioni. 2*X+Y //esempio di espressione N.B. il tipo degli operandi deve essere compatibile con il tipo degli operatori. (Es. non posso moltiplicare un carattere e un numero!) Tipicamente il risultato di una espressione è memorizzato in una variabile mediante l’operatore di assegnamento. Z = 2*X+Y; Operatori aritmetici + addizione - sottrazione * moltiplicazione / divisione % resto della divisione intera Questi operatori si applicano sia a numeri interi che a numeri frazionari. L’operatore / produce come risultato un intero se applicato a operandi interi, mentre ritorna un valore frazionario se applicato a operandi frazionari. Il risultato che si ottiene applicando tali operatori è di tipo numerico (intero o frazionario). X % Y, produce il resto della divisione intera fra gli interi X e Y. Es. 12 % 7 ritorna come valore 5. Esempi di espressioni aritmetiche int X=4,Y=12; double Z = 3.14; double W; W=((2*X-Z*Z)/2)+1; Y = (Y/X)%2; Esempi di espressioni aritmetiche int X=4,Y=12; double Z = 3.14; double W; W=((2*X-Z*Z)/2)+1; Y = (Y/X)%2; Y ha valore 1 W ha valore -0.0702 Operatori relazionali < <= > >= == != minore minore o uguale maggiore maggiore o uguale uguale diverso Questi operatori confrontano due espressioni e ritornano un valore booleano (true oppure false). Permettono di costruire espressioni booleane. N.B. non si confonda l’operatore di uguaglianza == con l’operatore di assegnamento =. Esempi di espressioni booleane int X=3,Y=5; double Z = 3.14; boolean W; W = ((X+1) == (Y*2)%6); Y = Z < X; Esempi di espressioni booleane int X=3,Y=5; double Z = 3.14; boolean W; W prende il valore true W = ((X+1) == (Y*2)%6); Y = Z < X; Y prende il valore false Operatori logici && and logico o congiunzione || or logico o disgiunzione ! not o negazione Questi operatori permettono di combinare assieme più espressioni booleane. Ritornano sempre un risultato di tipo booleano. Operatori logici e1 e2 e1&& e2 e1|| e2 !e1 true true true true false true false false true -- false true false true true false false false false -- Esempi di espressioni booleane int X=3,Y=5; double Z = 3.14; boolean W1,W2; W1 = (((X+1) == ((Y*2)%6))&& (3<4)) || !(9>=Z); W2 = (((X+1) != ((Y*2)%6))&& (3<4)) || !(9>=Z); Esempi di espressioni booleane int X=3,Y=5; double Z = 3.14; boolean W1,W2; W1 prende il valore true W1 = (((X+1) == ((Y*2)%6))&& (3<4)) || !(9>=Z); W2 = (((X+1) != ((Y*2)%6))&& (3<4)) || !(9>=Z); W2 prende il valore false Operatori ++ e -Questi operatori sono utilizzati, in notazione sia prefissa che postifissa, per incrementare o decrementare di 1 il valore di una variabile. Gli usi prefisso e postfisso di tali operatori non sono equivalenti. Esempio: { int K,X=3,Y,W,Z=4; Z++; Y = X++; W = ++X; K = W--; } // // // // postincremento postincremento preincremento postdecremento Operatori ++ e -Questi operatori sono utilizzati, in notazione sia prefissa che postifissa, per incrementare o decrementare di 1 il valore di una variabile. Gli usi prefisso e postfisso di tali operatori non sono equivalenti. Esempio: Z prende il valore 5 { int K,X=3,Y,W,Z=4; Z++; Y = X++; W = ++X; K = W--; } // // // // K prende 5 e W diventa 4 Y prende 3 e X diventa 4 postincremento postincremento preincremento postdecremento W prende 5 e X diventa 5 Strutture di controllo Sono istruzioni che permettono di modificare il flusso di esecuzione di un metodo • istruzioni condizionali • istruzioni iterative (cicli) Istruzioni condizionale La più comune istruzione condizionale è il blocco if-else, la cui sintassi è la seguente: if (<condizione>) <blocco di istruzioni 1> else <blocco di istruzioni 2> La condizione deve essere un’espressione booleana. Se la condizione è valutata true allora si esegue il blocco di istruzioni 1, altrimenti si esegue il blocco di istruzioni 2 Le parentesi graffe delimitanti i blocchi possono essere omesse quando i blocchi di istruzioni sono costituiti da un’unica istruzione. Istruzioni condizionali esempio if (X>0) System.out.println(“X è positivo”); else { System.out.print(“X è negativo ”); System.out.println(“oppure nullo”); } Istruzioni condizionali A volte il ramo else di una istruzione condizionale può essere assente. In tal caso l’istruzione assume la seguente forma: if (<condizione>) <blocco di istruzioni> Esegui il blocco di istruzioni se la condizione è valutata true. if (X%2==0) System.out.println(“X è pari”); Istruzioni condizionali È possibile unire più istruzioni if-else per esprimere più possibilità condizionali. La sintassi è la seguente if (<condizione 1>) <blocco di istruzioni 1> else if (<condizione 2>) <blocco di istruzioni 2> ... else <blocco di istruzioni n> Se la condizione 1 è valutata true, esegui il blocco di istruzioni 1, altrimenti se la condizione 2 è valutata true, esegui il blocco di istruzioni 2, ... altrimenti se nessuna condizione è verificata, esegui il blocco di istruzioni n. Istruzioni condizionali esempio if (X>0 && X<=10) System.out.println(X); else if (X==11) System.out.println(“Jack”); else if (X==12) System.out.println(“Regina”); else System.out.println(“Re”); Istruzioni condizionali: switch È possibile esprimere più possibilità condizionali, in maniera molto intuitiva, utilizzando l’istruzione switch. switch (<espressione>){ case <letterale 1>: <blocco istruzioni 1> case <letterale 2>: <blocco istruzioni 2> ... default: <blocco istruzioni n> } L’espressione deve produrre un risultato byte, short, int o char. Viene valutata l’espressione. Il risultato viene confrontato con ciascun case nell’ordine in cui questi compaiono. Se il risultato dell’i-esimo case coincide con il risultato dell’espressione allora tutti i blocchi di istruzioni da i a n vengono eseguiti. Se il risultato non coincide con nessun case allora si esegue il blocco di istruzioni n relativo al default. Istruzioni condizionali: switch (esempio) {int X=2; switch(X){ case 1: System.out.println(“Uno”); case 2: System.out.println(“Due”); default: System.out.println(“Default”); } } Questo codice stampa le stringhe Due e Default Istruzioni condizionali: break Nell’istruzione switch, se si vuole eseguire solo il blocco di istruzioni corrispondente al letterale uguale al risultato dell’espressione, si deve terminare il blocco di istruzioni con la parola chiave break. {int X=2; } switch(X){ case 1: System.out.println(“Uno”);break; case 2: System.out.println(“Due”);break; default: System.out.println(“Default”); } Questo codice stampa la stringa Due Istruzioni iterative: while L’istruzione while è una istruzione iterativa che permette di ripetere più volte l’esecuzione di una porzione di codice. La sintassi è la seguente: while(<condizione>) do <blocco di istruzioni da ripetere> la condizione deve essere un’espressione booleana. Finché il risultato dell’espressione è true, si ripete il blocco di istruzioni successivo. While (esempio) {int i=0; while(i<10){ System.out.println(i); i++; } } Questo codice stampa gli interi da 0 a 9 e alla fine del ciclo i vale 10 Istruzioni iterative: dowhile L’istruzione do-while è una istruzione iterativa che permette di ripetere più volte l’esecuzione di una porzione di codice. A differenza dell’istruzione while, le istruzioni da ripetere sono poste prima della condizione da valutare. Pertanto il blocco di istruzioni si ripete sempre almeno una volta! Sintassi: do <blocco di istruzioni da ripetere> while(<condizione>); la condizione deve essere un’espressione booleana. Finché il risultato dell’espressione è true, si ripete il blocco di istruzioni. Do-while (esempio) {int i=0; do { i++; System.out.println(i); } while(i<10); } Questo codice stampa gli interi da 1 a 10 e alla fine del ciclo i vale 10 Istruzioni iterative: for L’istruzione for è una istruzione iterativa che permette di ripetere più volte l’esecuzione di una porzione di codice. Sintassi: for(<inizializzazione>;<condizione>;<espressione>) <blocco di istruzioni da ripetere> L’espressione inizializzazione è tipicamente un’istruzione di assegnamento, che atribuisce ad una variabile di controllo un valore iniziale. La condizione è un’espressione booleana che tipicamente confronta il valore della variabile di controllo con un valore limite. L’espressione specifica il modo in cui la variabile di controllo deve essere modificata al termine di ogni iterazioni del ciclo. For (esempio) {int i; for(i=0;i<11;i++) System.out.println(i); } Questo codice stampa gli interi da 0 a 10 e alla fine del ciclo i vale 11 I vettori (o array) Il vettore (o array) è un oggetto che fornisce lo spazio di memoria per un elenco di elementi tutti dello stesso tipo componente T. Un vettore deve essere innanzitutto dichiarato mediante la seguente sintassi: <tipo>[] <nome_vettore>; int [] x,y; //dichiara x e y array di interi String [] frase; // dichiara un array di // stringhe di nome frase Creazione di un vettore Il tipo vettore è un tipo riferimento. Un riferimento ad un array si crea mediante l’operatore new. Quando si crea un vettore è necessario specificare la dimensione (ovvero il numero di celle allocate). new <tipo> [<dimensione>]; x = new int [10];//alloca un vettore di 10 //celle e memorizza il //riferimento nella //variabile vettore X frase = new String[3]; //la variabile frase //può contenere 3 stringhe Creazione di un vettore Un altro modo per creare un riferimento a un array consiste nel dare esplicitamente l’elenco dei valori da memorizzare in fase di dichiarazione. int[] x={14,12,1,24,7,1,2,9,9,11}; String[] frase={“questa”,”e’una”,”frase”}; Accesso e scrittura di un vettore Le componenti di un array sono indicizzate mediante un numero intero progressivo. Se l’array contiene n celle, la prima componente ha indice 0 e l’ultima ha indice n-1. La componente i-esima di un array può essere reperita o scritta usando la seguente sintassi: stampa ‘c’ <variabile di tipo array>[i] char[] lettere={’a’,’b’,’c’}; char j; mette ‘a’ in j System.out.println(lettere[2]); j=lettere[0]; scrive ‘k’ nella seconda lettere[1]= ‘k’; componente di lettere[] Matrici Una matrice è un vettore multidimensionale, in cui gli elementi memorizzati sono riferiti attraverso delle n-uple di indici. Ci limiteremo ad usare matrici di dimensione 2. Nel caso di dimensione 2, una matrice può essere interpretata come una griglia di valori (vettore di vettori). Ogni elemento di una matrice di dimensione 2 è indicizzato mediante una coppia di indici (numero di riga, numero di colonna). 0 1 2 0 1 2 5 1 10 1 3 9 0 7 8 elemento 7 identificato dalla coppia di indici (1,2) Matrici Una matrice deve essere innanzitutto dichiarata mediante la seguente sintassi: <tipo>[][] <nome_matrice>; int [][] x; //dichiara x matrice //bidimensionale di interi String [][] parole; // dichiara una matrice // di stringhe di nome // parole Creazione di una matrice Il tipo matrice è un tipo riferimento. Un riferimento ad una matrice si crea mediante l’operatore new. Quando si crea una matrice è necessario specificarne le dimensioni (i.e. numero di righe e numero di colonne).. new <tipo> [<dimensione1>][<dimensione2]; x = new int [10][3];//alloca una matrice di //10 righe e 3 colonne e //memorizza il riferimento //in x. parole = new String[2][2]; //parole può //contenere una da //tabella di stringhe //di 2 righe e 2 //colonne. Creazione di una matrice Un altro modo per creare un riferimento a una matrice consiste nel dare esplicitamente l’elenco dei valori da memorizzare (linearizzato per righe) in fase di dichiarazione. int[][] x={{14,12},{1,24},{7,1},{2,9}}; String[][] frase={{“ab”,”cd”},{”ef”,”gh”}}; Accesso e scrittura di una matrice Le componenti di una matrice sono indicizzate mediante coppie di numeri interi. Se la matrice ha n righe e m colonne, essa conterrà n*m celle. L’indice sulle righe può variare da 0 a n-1, mentre quello sulle colonne da 0 a m-1. La componente di riga i e colonna j di una matrice può essere reperita o scritta usando la seguente sintassi: stampa ‘c’ <variabile di tipo matrice>[i][j] char[][] l={{’a’,’b’},{’c’,’d’}}; char j; mette ‘a’ in j System.out.println(l[1][0]); j=lettere[0][0]; lettere[1][1]= ‘k’; scrive ‘k’ nella seconda componente della seconda riga e seconda colonna Le classi Un programma Java è un insieme di definizioni di classi. La sintassi per definire una classe è class <nome classe> { <corpo della classe> } il corpo di una classe è costituito da dichiarazione di variabili (attributi della classe) e da definizioni di metodi (comportamento della classe) Metodi Un metodo ha la seguente sintassi: <tipo> <nome_metodo> (<lista_parametri>) { <corpo del metodo> } dove tipo è il tipo del valore di ritorno del metodo, nome_metodo è un identificatore, lista_parametri è una sequenza (eventualmente vuota) di coppie tipo parametro che rappresenta i parametri di input del metodo, infine corpo del metodo è la definizione del metodo vera e propria. Se il tipo di ritorno è diverso da void (parola chiave che denota l’assenza di un valore di ritorno), il corpo del metodo deve terminare con la parola chiave return seguita dal valore che deve essere restituito. Esempi di metodi void stampamatrice() { int i,j; for(i=0;i<numero_righe;i++){ for(j=0;j<numero_colonne;j++) System.out.print(matrix[j][i]+" "); System.out.println(""); } } int somma_numeri(int m, int n) { int z; z=m+n; return z; } Esempi class Matrice { char [][] matrix; int numero_righe; int numero_colonne; Matrice(int n, int m) { } } matrix=new int [n][m]; numero_righe=n; numero_colonne=m; void stampaMatrice() { int i,j; for(i=0;i<numero_righe;i++){ for(j=0;j<numero_colonne;j++) System.out.print(matrix[j][i]+" "); System.out.println(""); } } Esempi di metodi tipo nome parametri void stampamatrice() { int i,j; for(i=0;i<numero_righe;i++){ for(j=0;j<numero_colonne;j++) System.out.print(matrix[j][i]+" "); System.out.println(""); } } corpo int somma_numeri(int m, int n) { int z; z=m+n; return z; } Metodo costruttore Un metodo costruttore è un metodo speciale che ha lo stesso nome della classe e che permette di creare oggetti (istanze) della classe. Nella definizione di tale metodo non compare il tipo di ritorno. Tipicamente un metodo costruttore definisce una lista di parametri attraverso i quali si assegnano dei valori agli attributi della classe. <nome_costruttore> (<lista_parametri>) { <corpo del metodo> } Un oggetto O di una classe C si crea invocando il metodo costruttore della classe e istanziando gli opportuni parametri. La sintassi è la seguente: new <nome_costruttore>(<valori_parametri>); Overloading In una classe è possibile definire metodi con nome uguale ma parametri distinti (e pertanto comportamento distinto). In questo caso si parla di overloading. class Esempio_overloading { void stampaDati(int n) { System.out.println("stampa numero "+n); } void stampaDati(String s) { System.out.println("stampa stringa "+s); } } Esempi class Matrice { char [][] matrix; int numero_righe; int numero_colonne; Matrice(int n, int m) { } } matrix=new int [n][m]; numero_righe=n; numero_colonne=m; attributi costruttore void stampaMatrice() { int i,j; for(i=0;i<numero_righe;i++){ for(j=0;j<numero_colonne;j++) System.out.print(matrix[j][i]+" "); System.out.println(""); } } metodo Esempi class Esempio_Uso_Classe_Matrx { void creaScacchiera() { int i,j; char colore=’b’; Matrix scacchiera= new Matrix(3,3); for(i=0;i<numero_righe;i++) for(j=0;j<numero_colonne;j++){ scacchiera[i][j]=colore; if (colore==’b’) colore=’n’ else colore=’b’; } } Ereditarietà È possibile derivare una classe B (chiamata sottoclasse) a partire da una classe A (chiamata superclasse). La sottoclasse B eredita tutti i metodi e gli attribuiti della superclasse. Inoltre in B possiamo definire nuovi metodi e nuovi attributi non presenti in A. Tale meccanismo è chiamato ereditarietà. SINTASSI: class <nome_sottoclasse> extends <nome_superclasse> { <corpo del sottoclasse> } Alcune proprietà È possibile definire il metodo costruttore della classe derivata a partire dal costruttore della superclasse utilizzando il costrutto super(<lista valori>); dove lista valori contiene i valori da passare come parametri al costruttore della superclasse. È possibile definire nella sottoclasse metodi che hanno lo stesso nome di alcuni metodi della superclasse, ma parametri e comportamento distinti (overriding). Esempio class Persona { String nome; String cognome; int eta; Persona(String n, String c, int e){ nome=n; cognome=c; eta=e; } void stampaDati() { System.out.println("Salve, sono una persona e mi chiamo "+nome); System.out.println("Ho "+eta+" anni"); } public void modificaNome(String n) { nome=n; } public String ottieniNome() { return “Mr.”+nome; } } Esempio public class Studente extends Persona { // sottoclasse derivata dalla classe Persona int matricola; // costruttore della sottoclasse Studente // si richiama il costruttore della sopraclasse // Persona mediante l'istruzione super public Studente(String n, String c, int e, int m) { super(n,c,e); matricola=m; } public void stampaDati() { System.out.println("Salve, sono uno stuente e mi chiamo "+ nome+" "+cognome); System.out.println("Ho "+eta+" anni"+ " e il mio numero di matricola e' "+matricola); } } public void modificaMatricola(int matr) { matricola=matr; } Interfacce Un’interfaccia permette di definire una serie di prototipi di metodi che saranno successivamente implementati da una o più classi. Un’interfaccia si definisce nel seguente modo: interface <nome_interfaccia> { <corpo dell’interfaccia> } dove nel corpo dell’interfaccia si definisce una lista di segnature di metodi (i.e. intestazioni di metodi). Esempio interface Figura { double Area(); double Perimetro(); } Interfacce Una classe può implementare una o più interfacce usando la seguente sintassi: class <nome_classe> implements <nome_interfaccia1>, <nome_interfaccia2> { <corpo della classe> } Class Rettangolo implements Figura { double base; double altezza; double xcoord; double ycoord; Rettangolo(x,y,a,b){ base=b;altezza=a;xcoord=x;ycoord=y; } double Area(){ return base*altezza; } double Perimetro(){ return 2*base+2*altezza; } } La classe Random la classe Random è una classe predefinita che permette di generare numeri pseudocasuali. È contenuta nel package java.util e pertanto per poterla utilizzare è necessario importare tale package con l’istruzione import java.util.Random; che deve essere posta all’inizio della definizione della classe che userà la classe Random. Per maggiori informazioni... http://java.sun.com/j2se/1.4.2/docs/api/java/util/Random.html La classe Random Alcuni metodi della classe Random: • Random() costruisce un oggetto della classe Random • nextInt() genera un numero intero pseudo casuale • nextInt(int n) genera un numero casuale compreso • tra 0 e n-1 nextDouble()genera un numero di tipo double compreso tra 0.0 e 1.0. Uso della classe Random Tipicamente per poter utilizzare i metodi della classe si seguono i seguenti passi: 1) si dichiara una variabile R della classe Random 2) si istanzia un oggetto della classe Random e si memorizza nella variabile R 3) Si invoca il metodo desiderato attraverso R 4) si memorizza il numero casuale generato in una variabile del tipo opportuno. Esempio { Random R; int X; //Dichiarazione della variabile //di tipo Random R = new Random(); //Generazione di un //oggetto di tipo Random //e suo assegnamento alla //variabile R X = R.nextInt(15); //invocazione del metodo //nextInt, che genera un //numero pseudocasuale //compreso fra 0 e 14 e //assegnazione del numero //generato alla variabile // di tipo intero X } La classe String • La classe String permette di rappresentare sequenze di caratteri (i.e. stringhe). • Tale classe è dotata di numerosi metodi per la manipolazione delle stringhe. • Maggiori informazioni al link http://java.sun.com/j2se/1.4.2/docs/api/java/lang/String.html Alcuni metodi della classe String • Costruttori String() - costruisce una stringa vuota Es. String s=new String(); String(String s1) - costruisce una stringa e assegna ad essa il contenuto della stringa s1. Es. String s=new String(”pippo”); Stesso effetto con: String s=”pippo”; length() - calcola la lunghezza di una stringa es. String s=new String(”pippo”); int l=s.length(); // l=5 charAt(int i) - seleziona l’i-esimo carattere della stringa. es. String s=new String(”pippo”); char c=s.charAt(4); // c=’o’ equals(Object s) - confronta la stringa con l’oggetto s1. Se sono uguali torna true altrimenti false es. String s1=new String(”pippo”); String s2=new String(”pappa”); boolean uguali=s1.equals(s2); // uguali=false toUpperCase() - Converte i caratteri di una stringa in caratteri maiuscoli. es. String s=new String(”PipPo”); String s1= new String(s.toUpperCase()); // s1=”PIPPO” toLowerCase() - Converte i caratteri di una stringa in caratteri minuscoli. es. String s=new String(”PipPo”); String s1= new String(s.toLowerCase()); // s1=”pippo” substring(int i, int j) - seleziona la sottostringa dalla posizione i (inclusa) alla posizione j (esclusa). es. String s=new String(”Cappotto”); String s2= new String(s.substring(4,s.length())); // s2=”otto” concat(String s) - Concatena la stringa con la stringa s. es. String s1=new String(”No”); String s2= new String(”Where”); s1=s1.concat(s2); //s1=”NoWhere” Nota: per concatenare due stringhe potete sempre usare l’operatore +. Es. “No”+”Where” -> “NoWhere” Applet • Sono programmi scritti in Java che possono • essere scaricati dalla rete • essere eseguiti direttamente nei browser Applet in Java • Ogni applet e’ implementato come sottoclasse della classe predefinita java.applet.Applet • Ogni applet deve implementare (ridefinire) alcuni metodi ereditati dalla classe java.applet.Applet • • • • • init() start() paint(Graphics g) stop() destroy() il metodo paint • Permette di disegnare degli oggetti grafici nella finestra del browser. • Prende in input come parametro un oggetto della classe Graphics. • Graphics è una classe predefinita che permette di disegnare delle figure geometriche. Un semplice esempio import java.applet.Applet; import java.awt.Graphics; public class HelloWorld extends Applet { public void paint(Graphics g) { g.drawString("Hello world!", 50, 25); } } Applet nelle pagine Web Per inserire un applet in una pagina Web è necessario usare il tag HTML Applet nel seguente modo: <APPLET code=”<nomeApplet.class>” codebase=”<percorso/URL dell’applet>” width=”<larghezza dell’area grafica dell’applet>” height=”<altezzadell’area grafica dell’applet>” > Esempio: <APPLET code=”HelloWorld.class” codebase=”.” width=”500” height=”500” > La classe Graphics alcuni metodi Graphics() - è il costruttore dellaclasse e permette di istanziare un nuovo oggetto della classe drawLine(int x1, int y1, int x2, int y2) - disegna un segmento di retta i cui estremi sono i punti (x1,y1) e (x2,y2) drawOval(int x, int y, int width, int height) - disegna un ovale con angolo superiore sinistro di coordinate (x,y), largo width e alto height. drawRect(int x, int y, int width, int height) - disegna un rettangolo il cui vertice in alto a sinistra ha coordinate (x,y), largo width e alto height. La classe Graphics alcuni metodi drawArc(int x, int y, int width, int height, int startangle, int arcangle) - disegna un arco che origina in (x,y), largo width, alto height, il cui angolo iniziale e! startangle el!angolo dell!arco e! arcangle. drawString(String s,int x, int y) - stampa s alle coordinate (x,y). setColor(Color c) - setta il colore al colore Color.c Alcuni valori possibili per c: black, blue, cyan, darkGray, orange, pink, red, yellow, magenta, white. fillRect(int x, int y, int width, int height) - disegna un rettangolo e lo riempie con colore selezionato La classe Graphics alcuni metodi fillOval(int x, int y, int width, int height) - disegna un ovale e lo riempie con il colore selezionato. fillArc(int x, int y, int width, int height, int startangle, int arcangle) - disegna un arco e lo riempie fino alla corda con il colore selezionato. drawPolygon(int[] x, int[] y, int n) - disegna un poligono di n vertici. Le coordinate dei vertici sono date mediante gli array di interi x[] e y[]. fillPolygon(int[] x, int[] y, int n) - disegna un poligono di n vertici e lo riempie con il colore selezionato.