Materiale didattico per gli studenti del corso di laurea in Scienze e Tecnologie per l’Ambiente
frequentanti l’insegnamento (parte informatica INF-01):
-
Metodologie Statistiche per L’Ambiente (DM 270)
Metodologie Statistiche per l’Analisi di Dati Ambientali (DM 509)
Docente: Sergio Orefice ([email protected])
Programma del corso AA 2008-09:
- Architettura dei sistemi informatici:
Generalità sui sistemi informatici. Architettura dei sistemi informatici: hardware e software.
- Codifica binaria dell'informazione:
Sistemi di numerazione posizionali. Sistema binario. Sistemi ottale ed esadecimale.
Conversioni di base.
- Elementi di logica booleana:
Porte logiche AND, OR, NOT, NAND, NOR, XOR. Tavole di verità. Circuiti combinatori.
- Il modello di von Neumann:
Architettura della macchina di von Neumann. Organizzazione della RAM. Organizzazione
della CPU.
- Algoritmi e programmi:
Concetto di algoritmo. Diagrammi di flusso. Strategie di progettazione di algoritmi. Ricorsione.
Ricerca sequenziale e ricerca binaria. Programmi e linguaggi di programmazione.
Grammatiche. Ambienti di programmazione.
- Basi di dati:
Relazioni e basi di dati relazionali. Operazioni su basi di dati relazionali.
- Sistema Operativo:
Architettura del sistema operativo. Processi.
- Alberi Binari e algoritmi di visita (** solo per studenti DM 509 **)
1. Architettura dei sistemi informatici
1.1
Generalità sui sistemi informatici
Definire in modo “preciso” e allo stesso tempo “sintetico” che cos’è l’informatica non è semplice,
infatti l’informatica ormai abbraccia campi vastissimi tanto da rendere le varie definizioni che
spesso si danno vaghe, contraddittorie o riduttive. Il termine informatica traduce il termine inglese
computer science (scienza dell’elaboratore), ma in realtà il calcolatore è solo lo strumento finale col
quale vengono realizzate le applicazioni. Una definizione generale che possa abbracciare tutte le
discipline dell’informatica, ma non generale al punto tale da includere campi che effettivamente non
sono correlati ad essa, e che è stata anche accettata dal Ministero della Pubblica istruzione è la
seguente: l’informatica è la scienza della rappresentazione e dell’elaborazione dell’informazione.
Questa impostazione evidenzia che il prodotto principale della tecnologia informatica è
l’informazione e come essa viene strutturata ed elaborata, non è difficile quindi capire perché
l’informatica oggi stia diventando parte integrante di quasi tutte le attività umane. Ci sono diverse
tipologie di sistemi informatici che vanno dal più piccolo personal computer portatile al più grande
sistema informatico con molteplici utenti e grandi quantità di dati e programmi usato in
un’industria, ma nonostante le notevoli differenze, è possibile individuare degli elementi comuni a
tutti questi sistemi e studiarne le caratteristiche.
1.2
Architettura dei sistemi informatici: hardware e software
Per architettura di un sistema informatico si intende:
 le componenti che formano il sistema;
 i compiti che ogni componente svolge nel sistema;
 come le varie componenti interagiscono tra loro.
La prima grande suddivisione che conviene adottare consiste nel distinguere l’hardware, cioè
l’insieme dei componenti fisici del sistema, dal software, cioè l’insieme dei programmi che
vengono eseguiti dal sistema.
SOFTWARE
firmware
HARDWARE
In realtà il confine è sottile: tra l’hardware ed il software c’è il firmware, ossia del software che è
implementato direttamente sull’hardware e non può essere cambiato. Come esempio, si considerino
due sistemi informatici quali un personal computer e un videogioco. Con il sistema videogioco è
possibile solo giocare perché è stato realizzato tramite firmware, ossia l’hardware della macchina è
stato realizzato in modo da implementare solo il gioco; invece con il personal computer è possibile
svolgere differenti attività come scrivere documenti di testo, disegnare immagini, ascoltare musica,
questo perché sul portatile c’è del software e quindi l’hardware è stato realizzato in modo da poter
accettare ed eseguire diversi programmi.
I principali componenti hardware sono:
 Unità di elaborazione o processore (indicata anche come CPU dall’inglese Central Processing
Unit) è la componente che si occupa di elaborare i dati e coordinare il trasferimento degli stessi
all’interno del sistema. Ha il compito di eseguire i programmi, cioè interpretare ed eseguire le
istruzioni che compongono i programmi stessi.
 Memoria centrale (indicata anche come RAM dall’inglese Random Access Memory) è la
componente che si occupa di memorizzare dati e programmi.
Le caratteristiche della memoria centrale sono:
o
capacità limitata ossia permette di memorizzare una quantità ridotta di dati o
programmi;
o
è volatile cioè il suo contenuto viene perduto quando viene spento
l’elaboratore, in presenza di guasti o di interruzioni di energia elettrica.
o
accesso alle informazioni veloce.
Si noti che affinché le informazioni possano essere elaborate il passaggio nella RAM è
obbligatorio.
 Memoria secondaria (o memoria di massa) anch’essa memorizza dati e programmi ma le sue
caratteristiche sono opposte a quelle della memoria centrale:
o
capacità elevata ossia consente la memorizzazione di quantità elevate di
informazioni;
o
è persistente cioè l’informazione non viene persa in caso di mancanza di
energia elettrica;
o
accesso alle informazioni lento.
Tutte le informazioni devono poter essere disponibili nel tempo per poter essere
utilizzate, altrimenti la loro elaborazione sarebbe inutile. E’ necessario quindi disporre di
archivi che possano contenere quantità elevate di informazioni. A questo serve la
memoria di massa che dunque è indispensabile come unità di archiviazione.
 Unità periferiche sono le componenti che permettono lo scambio di dati tra il calcolatore e
l’ambiente esterno. Le più comuni sono:
o Terminali dotati di una tastiera e di un video;
o Stampanti che producono uscite di tipo cartaceo.
 Bus di sistema è l’unità che collega tutte le componenti hardware permettendo lo scambio di
dati tra le stesse.
Il software si divide in due livelli principali:
 software di base, cioè programmi dedicati alla gestione dell’elaboratore e quindi di tutte le sue
componenti. Il principale programma del software di base è il sistema operativo, che gestisce e
coordina l’uso, da parte del software applicativo, di risorse hardware presenti nell’elaboratore
 Il sistema operativo consente:
o
il funzionamento dell’elaboratore (se non è presente il sistema operativo il
calcolatore non può essere avviato);
o
l’interazione con l’elaboratore ( senza di esso non sarebbe possibile comunicare con
la macchina che diventerebbe inutilizzabile).
 software applicativo, cioè programmi sviluppati per risolvere le specifiche esigenze
dell’utente. Esso opera al di sopra del software di base.
UTENTE
SOFTWARE APPLICATIVO
SOFTWARE DI BASE
HARDWARE
firmware
Esempi di sistemi informatici
Le tipologie più diffuse di sistemi informatici sono le seguenti:
o Personal Computer solitamente è composto da :

un corpo “box” che comprende il processore,la memoria centrale
e la memoria di massa, e ad esso sono collegati:

una tastiera e

un video.
Un personal computer generalmente ha il processore dedicato ad un unico utente.
La memoria di massa di un personal computer è costituita da due elementi:

disco fisso (hard disk) che ha un’elevata capacità ma è
inamovibile;

dischetti (floppy disk) che hanno capacità ridotta ma sono
estraibili e dunque portabili.
La memoria di massa, sia essa dischetti o disco fisso, è organizzata in archivi o file; un file ha un
proprio nome che ne permette l’individuazione all’interno della memoria di massa e può contenere
vari tipi di dati organizzati in vari modi. Per esempio può contenere testo, immagini, canzoni, ecc…
o Workstation solitamente è composta da :
 un video di grandi dimensioni;
 un processore capace di elevate prestazioni.
.
o Mini calcolatore è in grado di servire alcune decine di utenti, ciascuno collegato al mini
calcolatore tramite un terminale.
o Main frame capaci di gestire centinaia di utenti, con molti processori e grandi memorie di
massa. Ne sono un esempio i sistemi informatici per la gestione dei conti correnti di una banca,
o delle prenotazioni dei viaggi aerei.
o Reti di calcolatori sono sistemi informatici connessi tra loro. Le reti di calcolatori si
differenziano in due categorie principali:
 reti locali che collegano terminali e calcolatori che sono fisicamente vicini
fra loro (stesso edificio o stesso ufficio) e sono molto veloci, cioè capaci di
trasmettere grandi quantità di dati in poco tempo;
 reti geografiche che collegano fra loro elaboratori medio-grandi posti a
grande distanza fra loro (diverse regioni o diverse nazioni). La trasmissione
dell’informazione e più lenta e onerosa rispetto ad una rete locale.
2. Codifica binaria dell’informazione
L’informazione (I) intesa come numeri, caratteri, testi, immagini e quant’altro si possa
memorizzare, in un sistema informatico è rappresentata (o codificata) in forma binaria, cioè
attraverso una sequenza di zero e uno.
I
sequenza di zero e uno
L’unità di informazione elementare in un sistema informatico è il bit.
I
sequenza di bit
Il bit corrisponde allo stato di un dispositivo fisico e può avere solo due valori: zero oppure:
0
stato di tensione elettrica alto
1
stato di tensione elettrica basso
BIT
La scelta di limitarsi a due stati, zero e uno, è dettata da motivazioni tecnologiche quali la minor
probabilità di guasti ed errori.
Come le unità di misura da noi comunemente usate come il metro, il grammo, ecc…, anche il bit ha
dei multipli che sono:
o
Byte
che corrisponde a 8 bit;
o
Kbyte
che corrisponde a 1024 byte;
o
Mbyte
che corrisponde a 10242 byte;
o
Gbyte
che corrisponde a 10243 byte.
2.1
Caso di studio: codifica binaria di numeri naturali
Si indichi con M un generico numero naturale e con ai l’i-esimo bit della sequenza binaria che
codifica il numero M:
M
an an-1 … ai
…a1 a0
indica il bit più significativo
CASO A:
M
an an-1 … ai
indica il bit meno significativo
…a1 a0
La codifica da sequenza binaria a numero naturale avviene secondo la seguente formula:
n
M =  ai x 2i = an x 2n + an-1 x 2n-1 + …………+ a1 x 2 + a0 x 20
i=0
Esempio: trovare il numero naturale che corrisponde alla stringa binaria 101001011.
M = 1 x 28 + 0 x 27 + 1 x 26 + 0 x 25 + 0 x 24 + 1 x 23 + 0 x 22 + 1 x 21 + 1 x 20 =
= 256 +64 + 8 + 2 + 1 = 331
Esempio: trovare il numero naturale che corrisponde alla stringa binaria 1101001.
M = 1 x 26 + 1 x 25 + 0 x 24 + 1 x 23 + 0 x 22 + 0 x 21 + 1 x 20 =
= 64 + 32 + 8 + 1 = 105
Un modo più veloce per effettuare la codifica è considerare solo gli addendi che hanno uno
come fattore moltiplicativo (ossia i bit posti a uno): lo zero infatti dà un contributo nullo
nella moltiplicazione e quindi nell’addizione. L’esempio appena svolto può essere così
risolto nel seguente modo più rapido:
M = 1 x 26 + 1 x 25 + 1 x 23 + 1 x 20 =
= 64 + 32 + 8 + 1 = 105
L’uno nella moltiplicazione è un fattore neutro, e quindi può anch’esso essere omesso. In
questo modo otteniamo la seguente codifica:
M = 26 + 25 + 23 + 20 =
= 64 + 32 + 8 + 1 = 105
CASO B:
an an-1 … ai
M
…a1 a0
La codifica da un numero naturale alla corrispondente sequenza binaria avviene in accordo alle
seguenti regole:
 Si effettuano successive divisioni per due del numero, fino a portarlo a zero;
 Si considera la sequenza di bit (zero e uno) ottenuta, prendendo nell’ordine
generato (dal bit meno significativo a quello più significativo) i resti della
divisione. Informalmente possiamo dire che i resti vanno letti al contrario,
cioè dal basso verso l’alto.
Esempio : convertire in binario il numero 331.
331 : 2 = 165
165 : 2 = 82
82 : 2 = 41
41 : 2 = 20
20 : 2 = 10
10 : 2 = 5
5:2= 2
2:2= 1
1:2= 0
con resto di
con resto di
con resto di
con resto di
con resto di
con resto di
con resto di
con resto di
con resto di
331
1
1
0
1
0
0
1
0
1
bit meno significativo
bit più significativo
101001011
Esempio : convertire in binario il numero 2010.
2010 : 2 = 1005
1005 : 2 = 502
502 : 2 = 251
con resto di
con resto di
con resto di
0
1
0
bit meno significativo
251 : 2 = 125
125 : 2 = 62
62 : 2 = 31
31 : 2 = 15
15 : 2 = 7
7:2= 3
3:2= 1
1:2= 0
con resto di
con resto di
con resto di
con resto di
con resto di
con resto di
con resto di
con resto di
2010
1
1
0
1
1
1
1
1
bit più significativo
11111011010
2.2 Sistema di numerazione posizionale
Il sistema binario è un caso particolare di sistema di numerazione posizionale.
Definizione:
Un sistema di numerazione posizionale è definito da una coppia (base p, alfabeto A di cifre),
in cui le cifre appartenenti all’alfabeto A assumono i valori compresi fra zero e p-1.
A = {ai : 0 < ai < p-1}
Esempio:
sistema binario:
p=2,
A = {0,1}
sistema decimale:
p = 10 ,
A = {0,1,2,3,4,5,6,7,8,9}
2.3 Conversioni di base
In generale il valore decimale del numero M in base p è dato dalla formula:
n
M =  ai x pi
i=0
dove an an-1 ……a1 a0 è la sequenza che codifica Mp (con ai  A)
Con questa formula si può codificare una stringa in una qualsiasi base p nell’equivalente nmero
decimale.
Esempio:
58710 = 5 x 102 + 8x 101 + 7 x 100
425 = 4 x 51 + 2 x 50 = 2210
1213 = 1 x 32 + 2 x 31 + 1 x 30 = 1610
Si noti che in generale cifre di un numero non vanno lette come in un sistema di
numerazione decimale, ma come stringa di cifre in una certa base.
Ad esempio, 4510
non va letto “quarantacinque”, ma come stringa “quattro cinque” in base dieci
2.4 Sistemi ottale ed esadecimale
Nei calcolatori, oltre al sistema binario, sono spesso usati ed hanno particolare importanza i sistemi
ottale ed esadecimale in quanto permettono una rappresentazione dell’informazione più sintetica
rispetto alla codifica binaria.
 Sistema ottale:
 Sistema esadecimale:
base
p=8
alfabeto
A = {0,1,2,3,4,5,6,7}
base
p = 16
alfabeto
A = {0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F}
0 ≤ ai ≤ p-1
10
15
Altre conversioni di base
OTTALE
Esempio:
DECIMALE
convertire in decimale il numero ottale 534.
5348 = 5 x 82 + 3 x 81 + 4 x 80 = 320 + 24 + 4 = 34810
ESADECIMALE
Esempio:
DECIMALE
convertire in decimale il numero esadecimale B7F.
B7F16 = 11 x 162 + 7 x 161 + 15 x 160 = 2816 + 112 + 15 = 294310
Osservazione:
B7F16 = a2 a1 a0
con
a2 = 11
a1 = 7
a0 = 15
OTTALE
Per le conversioni : DECIMALE
ESADECIMALE
occorre passare prima per la codifica binaria.
Le conversioni binario-ottale e binario-esadecimale sono molto semplici, basta considerare il
seguente schema che associa a ogni cifra ottale (esadecimale) una corrispondente tripla (quadrupla)
binaria:
CIFRA OTTALE
TRIPLA BINARIA
0
1
2
3
4
5
6
7
CIFRA
ESADECIMALE
000
001
010
011
100
101
110
111
0
1
2
3
4
5
6
7
8
9
A
B
C
D
E
F
QUADRUPLA
BINARIA
0000
0001
0010
0011
0100
0101
0110
0111
1000
1001
1010
1011
1100
1101
1110
1111
Le tripla e le quadruple sono ottenute per mezzo della codifica binaria della rispettiva stringa ottale
e esadecimale. Si noti che in generale con n bit si possono codificare 2n numeri (tutti i numeri da 0 a
2n-1).
BINARIO
OTTALE
Si divide il numero binario in triple e si codifica ogni tripla nella corrispondente cifra ottale. Se il
numero binario non è multiplo di tre si aggiungono tanti zero a sinistra fino ad ottenere comunque
delle triple senza alterare il valore del numero.
Esempio: convertire in ottale il numero binario 1010110111
001 010 110 111
12678
1
2
6
7
Esempio: convertire in ottale il numero binario 111001100101
111 001 100 101
71458
7
1
4
5
BINARIO
ESADECIMALE
Si divide il numero binario in quadruple e si codifica ogni quadrupla nella corrispondente cifra
esadecimale. Se il numero binario non è multiplo di quattro si aggiungono zero a sinistra in modo
da ottenere comunque delle quadruple senza alterare il valore del numero.
Esempio: convertire in esadecimale il numero binario 1010110111
0010
1011
0111
2B716
2
B
7
Esempio: convertire in esadecimale il numero binario 101000111000
1010
0011 1000
A3816
A
DECIMALE
3
8
OTTALE
Questa codifica si può effettuare passando prima per la codifica binaria:
DECIMALE
BINARIO
OTTALE
Esempio:
convertire in ottale il numero decimale 4589610
45896 : 2 = 22948
22948 : 2 = 11474
11474 : 2 = 5737
5737 : 2 = 2868
2868 : 2 = 1434
1434 : 2 = 717
717 : 2 = 358
358 : 2 = 179
179 : 2 =
89
89 : 2 =
44
44 : 2 =
22
22 : 2 =
11
11 : 2 =
5
5:2=
2
2:2=
1
1:2=
0
con resto di
con resto di
con resto di
con resto di
con resto di
con resto di
con resto di
con resto di
con resto di
con resto di
con resto di
con resto di
con resto di
con resto di
con resto di
con resto di
4589610
0
0
0
1
0
0
1
0
1
1
0
0
1
1
0
1
bit meno significativo
bit più significativo
10110011010010002
A questo punto si spezza il numero binario in triple: 1 011 001 101 001 000
Il numero binario è composto di sedici cifre, per poter ottenere delle triple occorre dunque
aggiungere due zero a sinistra della stringa binaria:
001 011 001 101 001 000
1315108
1
3
1
5
1
0
In conclusione:
4589610
1315108
Esempio:
convertire in ottale il numero decimale 55510
555 : 2 =
277 : 2 =
138 : 2 =
69 : 2 =
34 : 2 =
17 : 2 =
8:2=
4:2=
2:2=
1:2=
277
138
69
34
17
8
4
2
1
0
con resto di
con resto di
con resto di
con resto di
con resto di
con resto di
con resto di
con resto di
con resto di
con resto di
55510
1
1
0
1
0
1
0
0
0
1
bit meno significativo
bit più significativo
10001010112
001 000 101 011
10538
1
0
5
3
In conclusione:
55510
DECIMALE
10538
ESADECIMALE
Anche questa conversione di base si può effettuare passando prima per la codifica binaria::
DECIMALE
BINARIO
ESADECIMALE
Esempio:
convertire in esadecimale il numero decimale 121310
1213 : 2 =
606 : 2 =
303 : 2 =
151 : 2 =
75 : 2 =
37 : 2 =
18 : 2 =
9:2=
4:2=
2:2=
1:2=
606
303
151
75
37
18
9
4
2
1
0
121310
0100
1011
con resto di
con resto di
con resto di
con resto di
con resto di
con resto di
con resto di
con resto di
con resto di
con resto di
con resto di
1
0
1
1
1
1
0
1
0
0
1
bit meno significativo
bit più significativo
100101111012
1101
4BD16
4
B
D
In conclusione:
121310
4BD16
Esempio: convertire in esadecimale il numero decimale 50710
507 : 2 = 253
253 : 2 = 126
126 : 2 = 63
63 : 2 = 31
31 : 2 = 15
15 : 2 = 7
7:2=
3
3:2=
1
1:2=
0
50710
0001
1111
con resto di
con resto di
con resto di
con resto di
con resto di
con resto di
con resto di
con resto di
con resto di
1111110112
1011
1FB16
1
1
0
1
1
1
1
1
1
bit meno significativo
bit più significativo
In conclusione:
50710
OTTALE
1FB16
BINARIO
Per codificare un numero ottale in un numero binario basta prendere ogni singola cifra del numero
ottale e codificarla nella corrispondente tripla binaria. Gli zeri a sinistra non contribuiscono al
valore del numero e possono essere omessi (ad es. 010 corrisponde a 10).
Esempio:
convertire in binario il numero ottale 1578
1
5
7
001 101 111
Esempio:
11011112
convertire in binario il numero ottale 543718
5
4
3
7
9
101 100 011 111 001
ESADEC.
1011000111110012
BINARIO
Per codificare un numero esadecimale in un numero binario basta prendere ogni singola cifra del
numero esadecimale e codificarla nella corrispondente quadrupla binaria. Gli zeri a sinistra non
contribuiscono al valore del numero e possono essere omessi (ad es. 0010 corrisponde a 10).
Esempio:
convertire in binario il numero esadecimale F2D516
F
2
D
5
1111
0010
1101
0101
11110010110101012
Esempio:
convertire in binario il numero esadecimale A3716
A
3
7
1010
0011
0111
1010001101112
3. Elementi di logica booleana
I circuiti hardware possono essere costruiti a partire da elementi primitivi, detti porte, che vengono
combinati tra di loro. Una porta è caratterizzata da un simbolo grafico e da una tavola di verità. Il
simbolo è la rappresentazione grafica della porta e la tavola di verità è una tabella che dà il valore
dell’uscita in funzione degli ingressi delle porte.
3.1
Porte logiche NOT, AND e OR
PORTA
NOT
PORTA
AND
PORTA
OR
ingresso
uscita
ingressi
uscita
ingressi
uscita
0
1
00
0
00
0
1
0
01
0
01
1
10
0
10
1
11
1
11
1
Si noti che le porte AND e OR possono anche avere più di due ingressi, mantenendo la stessa
semantica nella tavola di verità (ossia la porta AND ha 1 in uscita se e solo se tutti gli ingressi
hanno valore pari a 1, mentre la porta OR ha 1 in uscita se almeno uno degli ingressi ha valore 1).
3.2
Circuiti combinatori
Un circuito combinatorio è definito ricorsivamente come segue:
Definizione:
- Le porte sono circuiti;
- Se N1 e N2 sono circuiti allora lo sono anche:
N1
N1
N2
N1
N2
La tavola di verità di un circuito si ottiene considerando tutte le possibili configurazioni dei valori
degli ingressi e, per ognuna di esse, si calcola il valore dell’uscita risolvendo man mano i valori
relativi alle porte interne che compongono il circuito applicando la corrispondente tavola di verità.
(Si noti che gli ingressi di un circuito sono le linee che non provengono da alcuna porta, invece le
uscite sono quelle che non entrano in nessuna porta).
Esempio:
Si consideri il seguente circuito combinatorio e si determini la sua tavola di verità
i1
i2
i3
u
i4
i5
i6
ingressi
uscita
ingressi
uscita
000000
000001
000010
000011
000100
000101
000110
000111
001000
001001
001010
001011
001100
001101
001110
001111
0
0
0
1
0
1
0
1
1
1
1
1
1
1
1
1
010000
010001
010010
010011
010100
010101
010110
010111
011000
011001
011010
011011
011100
011101
011110
011111
0
0
0
1
0
1
0
1
1
1
1
1
1
1
1
1
3.3
ingressi
100000
100001
100010
100011
100100
100101
100110
100111
101000
101001
101010
101011
101100
101101
101110
101111
uscita
0
0
0
1
0
1
0
1
1
1
1
1
1
1
1
1
ingressi
uscita
110000
110001
110010
110011
110100
110101
110110
110111
111000
111001
111010
111011
111100
111101
111110
111111
0
0
0
1
0
1
0
1
0
0
0
1
0
1
0
1
Caso di studio: Multiplexer e Demultiplexer
Si noti anzitutto che ogni circuito è caratterizzato da:
o
una specifica, cioè la definizione formale del circuito, che è unica;
o
una o più implementazioni, cioè possibili realizzazioni del circuito che
soddisfino la specifica.
Vediamo adesso la specifica e una possibile implementazione di due comuni circuiti combinatori, il
Multilplexer e il Demultiplexer.
MULTIPLEXER
Il multiplexer è un circuito usato per selezionare un bit in ingresso e instradarlo verso l’uscita.
Specifica:
Il multiplexer è un circuito con:
 una linea di uscita w;
 n linee di ingresso a0, … … , an-1 dette linee dati;
 n linee di ingresso aggiuntive c0, … … , cn-1 dette linee gating con la condizione che
ad ogni istante solo una linea di gating ha valore 1 (linea attiva).
L’operazione svolta dal multiplexer è la seguente:
<< Se ci è la linea attiva, allora w = ai >>
Implementazione:
a0 c0
a1 c1
a2 c2
a3 c3
MULTIPLEXER 4 - 1
w
DEMULTIPLEXER
Il demultiplexer è usato per selezionare l’uscita del circuito sulla quale verrà instradato un bit in
ingresso. Esso è l’esatto contrario funzionale del multiplexer.
Specifica:
Il demultiplexer è un circuito combinatorio con:
 una linea di ingresso x detta linea data;
 n linee di ingresso addizionali c0, … … , cn-1 dette linee gating con la condizione che
ad ogni istante solo una linea di gating ha valore 1 (linea attiva).
 n linee di uscita y0, … … , yn-1
L’operazione svolta dal multiplexer è la seguente:
<< Se ci è la linea attiva, allora yi = x >>
Implementazione:
c0
c1
c2
c3
x
DEMULTIPLEXER 1-4
y0
4.1
y1
y2
y3
Porte NAND, NOR e XOR
Le porte NOT, AND e OR formano un sottoinsieme completo, ossia con esse è possibile
implementare un qualsiasi circuito combinatorio. Altre importanti porte comunemente usate nella
realizzazione di circuiti combinatori sono le seguenti:
PORTA
NAND
(è il contrario dell’ AND)
PORTA
NOR
(è il contrario dell’ OR)
PORTA
XOR
(è l’ OR esclusivo)
ingressi
00
uscita
1
ingressi
00
uscita
1
ingressi
00
uscita
0
01
1
01
0
01
1
10
1
10
0
10
1
11
0
11
0
11
0
Sia la porta NAND che la porta NOR sono singolarmente complete, ossia possono essere usate da
sole per realizzare qualsiasi circuito combinatorio. (Un circuito fatto di sole porte NAND o di sole
porte NOR è però in generale più complesso, dunque meno efficiente e più costoso da realizzare).
Vediamo, ad esempio, come è possibile costruire un circuito fatto di sole porte NAND equivalente
alle porte AND, OR e NOT. Ciò dimostra che la porta NAND è completa.
a
b
a
w
w
b
a
a
b
a
w
w
w
b
a
w
4. Il modello di Von Neumann
La macchina di Von Neumann offre un modello descrittivo di base dell’architettura di un
calcolatore.
BUS
CPU
RAM
PERIFERICHE
Nel modello di Von Neumann le periferiche includono anche la memoria di massa in quanto essa
interagisce col sistema in modo funzionalmente equivalente a dispositivi di input/output come
terminali o stampanti.
4.1
Organizzazione della RAM
La memoria centrale è fatta da una sequenza di celle o parole di memoria. Ogni parola è fatta da
una sequenza di bit e contiene un dato o un’istruzione.
0
Parola di memoria
1
n-1
bit
Si definisce dimensione della memoria il numero di celle di cui è composta la memoria stessa. A
ogni cella è associato un numero (o indirizzo) che va da 0 a n-1.
Per poter essere utilizzate le informazioni debbono poter essere reperite dalla memoria. Di qui la
necessità di selezionare una determinata cella in modo univoco. Ogni cella può essere selezionata (o
indirizzata) attraverso un registro che si trova nella CPU e che si chiama registro indirizzi. In
generale, un registro è un dispositivo della CPU capace di memorizzare una sequenza di bit.
La codifica binaria della sequenza di bit contenuta nel registro indirizzi dà l’indirizzo della cella da
selezionare. Pertanto se il registro indirizzi ha k bit si possono indirizzare 2k celle di memoria i cui
indirizzi vanno da 0 a 2k-1. L’equazione che lega la dimensione n della RAM e la dimensione k del
registro indirizzi è quindi:
n = 2k
Come esempio si consideri un registro indirizzi a 10 bit e una RAM con 210 = 1024 celle.
0
1
i
1023
Registro indirizzi
K = 10 bit
Si supponga inoltreche la parola di memoria che si vuole indirizzare sia quella con indirizzo pari a
23, allora il registro indirizzi conterrà il valore 23 in codifica binaria, cioè:
Una volta che è stata selezionata una parola di memoria possono essere effettuate due operazioni:
o
LETTURA
o
SCRITTURA
Entrambe le operazioni utilizzano un secondo registro della CPU che si chiama registro dati e ha la
stessa dimensione (cioè numero di bit) delle parole di memoria.
LETTURA :
Il contenuto della cella di memoria selezionata è trasferito nel registro dati.
SCRITTURA :
Il contenuto del registro dati è trasferito nella cella di memoria selezionata.
Il seguente disegno illustra lo schema del funzionamento generale della RAM:
Dimensione n = 210 = 1024
H =16 bit
Registro dati
0
1
L
S
i
H =16 bit
S = scrittura
L = lettura
Registro indirizzi
1023
K = 10 bit
4.2
Organizzazione della CPU
La struttura della CPU è la seguente::
La CPU è formata dalle seguenti componenti:
 ALU
L’unità aritmetico logica è un dispositivo capace di effettuare le operazioni
aritmetiche (somma, sottrazione,…) e logiche (and, or, not,…) di base fra i bit.
 CLOCK
Il clock (orologio) è un dispositivo che sincronizza (cioè abilita e
disabilita) le varie componenti.
 REGISTRI
Sono dispositivi che memorizzano bit. Essi sono caratterizzati dal
compito che svolgono e dalla dimensione. I principali registri sono:
o Registro dati (RD) contiene i dati o le istruzioni da leggere e
scrivere in memoria. Ha dimensione pari a h bit se h è la
lunghezza di una parola di memoria.
o Registro indirizzi (RI) contiene gli indirizzi delle celle di
memoria. Ha dimensione pari a k bit se 2k è la dimensione
della memoria.
o Registro istruzione corrente (RIC) contiene istante per istante
l’istruzione correntemente eseguita. Ha dimensione pari a h bit
se h è la lunghezza di una parola di memoria.
o Contatore di programma (PC) contiene l’indirizzo della cella
di memoria corrispondente alla prossima istruzione del
programma in esecuzione. Ha dimensione pari a k bit se k è la
dimensione del registro indirizzi.
o Accumulatore (A) contiene gli operandi e i risultati delle
operazioni fatte dall’ALU. Ha dimensione m  h se h è la
dimensione di una parola di memoria.
La CPU esegue le istruzioni attraverso il classico schema fetch-execute:
1.
Legge la nuova istruzione dalla RAM ponendola nel RIC;
2.
Cambia il PC affinché punti alla prossima istruzione da eseguire;
3.
Determina il tipo di istruzione appena prelevata;
4.
Se l’istruzione usa dei dati in RAM, determina dove sono situati;
5.
Prende i dati dal registro dati (RD);
6.
Esegue l’istruzione;
7.
Memorizza il risultato al posto giusto;
8.
Ritorna al passo 1 e comincia ad eseguire l’istruzione seguente.
Questo ciclo si chiama “ciclo preleva, decodifica, esegui” e sta alla base del funzionamento di tutti
i calcolatori. Il limite principale del modello di Von Neumann sta nel fatto che le istruzioni sono
eseguite in stretta sequenza l’una dopo l’altra non permettendo alcuna forma di parallelismo,
presente invece nelle moderne architetture di elaboratori.
5. Algoritmi e programmi
I sistemi informatici sono esecutori di algoritmi.
Definizione:
L’algoritmo è una sequenza di passi (istruzioni) che determinano la risoluzione di un
problema.
Un algoritmo viene caratterizzato da alcuni parametri quali:
CORRETTEZZA
ALGORITMO
COMPLETEZZA
EFFICIENZA
Un algoritmo è corretto se risolve il problema per cui è stato creato, ossia se per ogni input calcola
correttamente l’output.
Un algoritmo è completo se considera tutti i possibili casi appartenenti al problema, ossia se
funziona per tutti i possibili input.
L’efficienza di un algoritmo viene espressa in termini di “spazio” e “tempo”. Lo spazio si riferisce
alla quantità di memoria occupata dall’esecuzione dell’algoritmo, il tempo si riferisce ai tempi di
risposta, ossia i tempi necessari all’esecuzione dell’algoritmo per ottenere la soluzione del
problema.
5.1
Un pseudo-linguaggio per la descrizione di algoritmi
Un algoritmo è fatto da una intestazione, contenente il nome dell’algoritmo e i suoi parametri input,
e da un corpo, contenente le istruzioni. Nel seguito gli algoritmi verranno descritti utilizzando un
piccolo sottinsieme di istruzioni con la seguente sintassi e semantica:
BEGIN END
Ogni blocco di istruzioni va racchiuso tra due parole chiave che formano il costrutto begin end e
che indicano rispettivamente l’inizio e la fine di un insieme di istruzioni.
BEGIN
Istruzione1
Istruzione2
…………
END
IF THEN
Il costrutto if then è caratterizzato dal fatto che le istruzioni del blocco che seguono la parola chiave
then siano eseguite se e solo se la condizione posta dopo la parola chiave if risulta essere vera.
IF
(condizione)
THEN
blocco istruzioni
IF THEN ELSE
Il costrutto if then else è caratterizzato dal fatto che se la condizione posta dopo la parola chiave if è
vera allora sono eseguite le istruzioni del blocco posto dopo la parola chiave then, altrimenti (ossia
nel caso in cui la condizione risulti falsa) vengono eseguite le istruzioni poste dopo la parola chiave
else.
IF
(condizione)
THEN
blocco1 di istruzioni
ELSE
blocco2 di istruzioni
Ciclo WHILE
Un ciclo è un blocco di codice che itera (ripete) un certo numero di istruzioni finché la condizione
di controllo del ciclo risulta vera.
WHILE (condizione)
DO
blocco istruzioni
RETURN
Il costrutto return restituisce un valore di output provocando l’interruzione dell’esecuzione
dell’algoritmo stesso.
RETURN
valore
5.2 Strategie di progettazione di algoritmi.
Esistono due principali strategie di progettazione degli algoritmi: l’iterazione e la ricorsione.
ITERAZIONE
Un algoritmo si dice iterativo quando esegue ripetutamente una o più istruzioni, in accordo al
verificarsi di determinate condizioni.
Esempio:
Calcolo del fattoriale
n! = n x n-1 x n-2 x ………x 2 x 1
esempio:
4! = 4 x 3 x 2 x 1 = 24
Algoritmo:
Fattoriale (N)
BEGIN
k=1
i=1
i ≤ N DO
WHILE
BEGIN
k=kxi
i=i+1
END
RETURN
k
END
Esecuzione dell’algoritmo per N = 3:.
N
k
i
3
1
1
1
2
2
3
6
4
RICORSIONE
Si parla di ricorsione quando la soluzione di un problema può essere ottenuta riconducendola allo
stesso problema ma su dati più piccoli. Ad esempio, si osservi che per calcolare il fattoriale di N si
può calcolare il fattoriale di N-1 e moltiplicarlo per N, cioè:
N! = 1
per
N=1
N! = N x (N-1)!
per
N>1
Questa è una definizione ricorsiva perché riconduce l’esecuzione di un calcolo su un certo dato (N),
all’esecuzione dello stesso calcolo su un dato più piccolo (N-1).
Un algoritmo si definisce ricorsivo se nel suo corpo contiene una chiamata a sé stesso. La versione
ricorsiva dell’algoritmo per il calcolo del fattoriale è la seguente:
Algoritmo:
Fattoriale (N)
BEGIN
IF
ELSE
N=1
THEN
RETURN
RETURN
1
N x Fattoriale (N-1)
END
I passi che l’algoritmo esegue se viene chiamato con un valore di N pari a 3 sono i seguenti:
N
3
return 3 x Fattoriale (2)
2
return 2 x Fattoriale (1)
1
return 1
Ricalcolando all’indietro i valori di ritorno delle varie chiamate ricorsive si otterrà il risultato finale
6.
Si noti che la soluzione ricorsiva ad un problema non è sempre possibile, gli algoritmi ricorsivi sono
più efficienti e naturali quando la natura stessa del problema si presta bene alla ricorsione, cioè
quando::
Un problema si ripropone al suo interno in sottoproblemi uguali all’originale, ma applicati
a sottoinsiemi dei dati, e la soluzione globale si ottiene come combinazione delle soluzioni
dei sottoproblemi.
5.3
Ricerca sequenziale e ricerca binaria
I problemi di ricerca di un elemento sono tra i più comuni nell’elaborazione dei dati e hanno
tantissime applicazioni pratiche. Tipici elenchi di dati che incontriamo nella realtà sono:

l’insieme dei volumi in una biblioteca;

l’elenco degli impiegati di un’azienda;

le persone appartenenti all’anagrafe di una certa città.
La struttura che si utilizza per memorizzare questi elenchi di dati è il dizionario. Un dizionario è
una collezione di su cui è possibile effettuare operazioni di inserimento, eliminazione e ricerca. La
ricerca è l’operazione fondamentale, perché comunque propedeutica alle altre due.
RICERCA SEQUENZIALE
Metodo:
Il dato da cercare viene confrontato sequenzialmente con i dati del dizionario finchè
esso viene trovato (successo) oppure termina la scansione del dizionario (fallimento).
L’algoritmo di ricerca sequenziale è iterativo e sempre applicabile. Il costo
dell’algoritmo (cioè il numero di volte in cui viene ripetuta l’operazione
fondamentale di confronto) è lineare nella taglia del dizionario.
Sia A un dizionario con n elementi e k il dato da cercare:
Algoritmo:
Ricerca_sq ( k , A )
BEGIN
i=1
i≤n
WHILE
DO
BEGIN
k = A(i)
IF
ELSE
THEN
RETURN
kA
“Successo”
i=i+1
END
RETURN
kA
“Fallimento”
END
RICERCA BINARIA
La ricerca binaria è applicabile quando sul dizionario è definito un ordinamento.
Metodo:
Il dato k da cercare viene confrontato con l’elemento centrale x del dizionario.
Se k = x la ricerca termina con successo.
Se k < x la ricerca procede con lo stesso metodo sulla prima metà della tabella.
Se k > x la ricerca procede con lo stesso metodo sulla seconda metà della tabella.
L’algoritmo di ricerca binaria è pertanto ricorsivo, ed ha un costo logaritmico in quanto ad ogni
passo lo spazio di ricerca (e quindi il numero di confronti) viene dimezzato.
Sia A un dizionario con n elementi e k il dato da cercare, siano i e j gli estremi del dizionario
(all’inizio i=1, j=n):
Algoritmo:
Ricerca_Bin ( k , A , i , j )
BEGIN
IF
m =
END
i>j
THEN
RETURN
“Fallimento”
kA
i+j
2
IF
k = A (m)
THEN
RETURN
“Successo”
IF
k < A (m)
THEN
Ricerca_Bin ( k , A, i , m-1)
ELSE
Ricerca_Bin (k , A , m+1 , j )
kA
Esempio:
Dizionario ordinato con 18 elementi.
1
2
3
4
5
6
7
8
9
10
2
4
5
11
13
20
47
49
52
67
11
12
13
14
15
16
17
104 120 125 200 207 310 350 450
Sia k = 47 il dato da cercare:
Al primo passo :
i=1
j = 18
M = ( 1 + 18 ) / 2 = 9
A [ 9 ] = 52 > k
M= (1+8)/2
A [ 4 ] = 11 < k
Al secondo passo : i = 1
J=8
Al terzo passo :
Al quarto passo :
= 4
i=5
J=8
M= (5+8)/2
= 6
A [ 6 ] = 20 < k
M= (7+8)/2
= 7
A [ 7 ] = 47 = k
i=7
J=8
18
quindi k  A
5.4
Programmi e linguaggi di programmazione
I concetti di programma e algoritmo sono strettamente correlati:
Definizione: Un programma è la codifica di un algoritmo in un linguaggio di programmazione (in
modo che l’algoritmo possa essere eseguito su un calcolatore).
I linguaggi di programmazione si dividono in due grandi categorie:

general purpose, adatto a risolvere efficientemente ampie classi di problemi. Ne sono esempi
il C, Pascal, Java, etc.

specific purpose, adatti a risolvere efficientemente problemi in uno specifico dominio di
applicazione. Ne sono esempi il COBOL adatto per applicazioni gestionali e banche, Visual
Basic adatto per applicazioni grafiche, HTML adatto per applicazioni su Internet, etc.
Ogni linguaggio di programmazione è caratterizzato da una precisa sintassi e da una precisa
semantica. Da un punto di vista formale la definizione generale di linguaggio è la seguente:
Definizione: Un linguaggio formale è un insieme di stringhe su un alfabeto di simboli.
Esempio:
L = {ab , aab}
sull’alfabeto {a , b}
Linguaggio finito in quanto composto da un numero finito o contabile (due) di
stringhe.
L = {anb} con n  1
sull’alfabeto {a , b}
Linguaggio infnito in quanto composto da un numero infinito o non contabile di
stringhe (tutte le ripetizioni di ‘a’ con una ‘b’ alla fine).
Ogni linguaggio di programmazione è un linguaggio, infatti le stringhe del linguaggio sono tutti i
programmi sintatticamente corretti scritti in quel linguaggio di programmazione.
Grammatiche
Per specificare la sintassi (ossia la forma delle frasi) dei linguaggi si usa un formalismo chiamato
grammatica.
Definizione:
Una grammatica è una quadrupla G = (N, T, S, P) dove:

N è l’insieme finito di simboli non terminali;

T è l’insieme finito di simboli terminali;

S  N, è il simbolo non terminale iniziale;

P è l’insieme finito di produzioni del tipo A  con:
- A non terminale;
-  stringa di terminali e/o non terminali.
Definizione: Una derivazione (⇒) è l’applicazione di una produzione, ossia il rimpiazzamento
della parte destra con la parte sinistra
Ad esempio, A ⇒ 
Il simbolo
se A   è una produzione.
indica più passi di derivazione.
Definizione: Il linguaggio generato da una grammatica , L (G), è l’insieme delle stringhe di soli
terminali derivati dal simbolo non terminale iniziale:
L (G) = {w / S
w}
Esempio:
Scrivere una grammatica per il linguaggio L = {ab, ccb}
G = (N, T, S, P)
con
N = {S}
T = {a, b, c}
S=S
P = { S → ab
S → ccb}
oppure:
G = (N, T, S, P)
con
N = {S, A}
T = {a, b, c}
S=S
P = { S → Ab
A→a
A → cc}
Esempio:
Scrivere una grammatica per il linguaggio L = {an b} con n  1.
G = (N, T, S, P)
con
N = {S, A}
T = {a, b}
S=S
P = { S → Ab
A→a
A → aA}
La coppia di produzioni A → a A → aA usata per specificare ripetizioni infinite si chiama cappio.
Grammatica per espressioni aritmetiche
Definizione: Un’espressione è ricorsivamente definita come segue:

un numero è un’espressione;

se E è un’espressione lo sono anche:
- (E)
- E+E
- E–E
- E*E
- E/E
La grammatica che genera espressioni aritmetiche è la seguente:
G = (N, T, S, P)
N = {E, Num, C}
T = { (, ), +, *, /, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
S=E
P = { E → Num
E → (E)
E→E+E
E→E–E
E→E*E
E→E/E
Num → C
Num → Num C
C→0
C→1
C→2
C→3
C→4
C→5
C→6
C→7
C→8
C → 9}
Dove E sta per espressione, Num sta per numero e C sta per cifra.
Automi
Un altro formalismo per la specifica dei linguaggi sono gli automi. Le grammatiche generano i
linguaggi, ovvero esse generano le stringhe dei linguaggi; gli automi invece, riconoscono i
linguaggi, ossia data una stringa l’automa riconosce se la stringa appartiene o meno al linguaggio.
Definizione: Un automa è una quintupla
M = (Q, A, q0, F, t)
dove:
-
Q è l’insieme finito degli stati;
-
A è l’alfabeto;
-
q0  Q è lo stato iniziale;
-
F  Q è l’insieme degli stati finali;
-
t è la funzione di transazione del tipo t: Q x A → Q
Gli automi vengono descritti attraverso i diagrammi stati-transizioni. Una stringa è accettata, o
riconosciuta, se e solo se esiste un cammino che va dallo stato iniziale a quello finale del digramma.
Esempio:
Dare l’automa per il linguaggio L = {ab, aab}.
M = (Q, A, q0 , F, t)
con:
Q = {1, 2, 3, 4}
A = {a, b}
q0 = 1
F = {3}
t={
(1, a) = 2
(2, a) = 4
(2, b) = 3
(4, b) = 3 }
Diagramma stati-transizioni:
Esempio:
Descrivere l’automa del linguaggio L = {an b}.
M = (Q, A, q0 , F, t)
con:
Q = {1, 2, 3}
A = {a, b}
q0 = 1
F = {3}
t={
(1, a) = 2
(2, a) = 2
(2, b) = 3}
Diagramma stati-transizioni:
5.5 Ambiente di programmazione
Per poter scrivere ed eseguire programmi in un certo linguaggio di programmazione occorrono due
software applicativi, l’editor e il compilatore:
-
EDITOR serve per creare file di testo, in particolare per scrivere i programmi.
Il programma creato con l’editor si chiama programma sorgente.
-
COMPILATORE serve per tradurre il programma sorgente in linguaggio
binario direttamente eseguibile dall’hardware del calcolatore. Il programma
ottenuto dal compilatore si chiama programma target.
Questi due software applicativi formano un ambiente di programmazione di cui ogni linguaggio di
programmazione è fornito.
Ci sono vari tipi di editor, ad esempio:
- Word processor che permette di scrivere testi;
- Editor di ambienti di programmazione che permettono di scrivere programmi sorgente
per uno specifico linguaggio di programmazione.
- Editor grafici che permettono di creare oggetti grafici.
L’architettura di un compilatore è la seguente:
Programma
sorgente
Programma
target
COMPILATORE
errori
Tipicamente il compilatore opera secondo il modello ANALISI – SINTESI, dove i moduli software
di analisi si occupano di analizzare la correttezza del programma sorgente, mentre quelli di sintesi
derivano il formato target finale.
COMPILATORE
Programma
sorgente
ANALISI
Rappresentazione
intermedia
SINTESI
Programma
target
I compilatori si basano su specifiche grammaticali del linguaggio sorgente. Uno dei moduli
software più importanti nella parte di analisi è il Parser che, sostanzialmente, è un automa che
verifica se un programma sorgente è sintatticamente corretto oppure no, riconoscendolo o meno
come stringa appartenente al linguaggio generato dalla grammatica sorgente.
CICLO DI VITA DEI PROGRAMMI
Lo schema che modella la risoluzione automatica dei problemi tramite algoritmi/programmi è il
seguente:
PROBLEMA
Il programmatore progetta un ALGORITMO per la soluzione del problema
Il programmatore scrive, utilizzando un editor, un PROGRAMMA sorgente in un certo linguaggio
di programmazione che codifica l’algoritmo
Il programma viene COMPILATO per mezzo del compilatore dello specifico linguaggio
Il programma target viene ESEGUITO
L’esecuzione finale del programma target fornisce la soluzione del problema di partenza.
6. Basi di dati
Nella vita quotidiana può capitare spesso di consultare una base di dati, quando ad esempio si
consulta l’elenco telefonico o le pagine gialle, oppure il tabellone degli orari di partenza e arrivo dei
treni. Quando grandi quantità di dati sono mantenute nei calcolatori, occorrono software particolari
per la loro organizzazione e per la loro gestione. Questi software applicativi si chiamano DBMS
(Data Base Management Systems) e sono tra i più importanti software applicativi dei calcolatori.
Esistono tre tipologie di basi di dati che variano a seconda del tipo di strutturazione dei dati:
- Basi di dati gerarchiche caratterizzate da un’organizzazione gerarchica dei dati (le
strutture dati sono alberi);
- Basi di dati reticolari caratterizzate da un’organizzazione reticolare dei dati (le strutture
dati sono grafi);
- Basi di dati relazionali caratterizzati da un’organizzazione tabellare dei dati (le
strutture dati sono tabelle).
ALBERO
GRAFO
TABELLA
6.1 Relazioni e basi di dati relazionali
Nel seguito introduciamo alcune definizioni e nozioni di base sulle basi di dati relazionali:
Definizione: Una base di dati relazionale è un insieme di relazioni.
Definizione: Una relazione è una tabella con un numero fisso di colonne (che rappresentano gli
attributi) e un numero variabile di righe (che sono dette tuple).
Esempio:
La relazione conto-corrente può essere rappresentata nel seguente modo:
NUMERO C.C.
NOME
INDIRIZZO
SALDO
1
Rossi
Via anemoni 5
2
Bianchi
Via bolla 64
664,00
3
Brunelli
Via Dante 41
2564,60
4
Grandi
Via Romolo 3
1.700,20
3.678,00
Definizione: Lo schema di una relazione è definito dal nome della relazione e dall’elenco dei suoi
attributi.
Esempio:
Lo schema della precedente relazione conto-corrente è:
(CONTO-CORRENTE, (numero c.c., nome, indirizzo, saldo) )
Definizione: L’istanza di una relazione è l’insieme delle tuple della relazione presenti in un
particolare istante di tempo.
Esempio:
L’istanza della relazione conto-corrente in un determinato momento è:
1
Rossi
Via anemoni 5
3.678,00
2
Bianchi
Via bolla 64
664,00
3
Brunelli
Via Dante 41
2564,60
4
Grandi
Via Romolo 3
1.700,20
Si noti che lo schema di una relazione è fisso, mentre l’istanza è variabile.
Definizione: Lo schema di una base di dati relazionale è dato dall’insieme degli schemi delle
relazioni presenti nella base di dati.
Esempio:
Lo schema di una base di dati che raccoglie informazioni sugli studenti di una
università potrebbe essere del tipo:
( (STUDENTE, (matricola, nome, data-nascita, anno-corso, corso-laurea) ),
(CORSO, (codice-corso, titolo, docente) ),
(ESAME, (codice-corso, matricola-studente, data, voto) ) )
Definizione: L’istanza di una base di dati relazionale è data dall’insieme di tutte le istanze delle
relazioni presenti nella base di dati in un particolare istante di tempo.
Definizione: La chiave di una relazione è il sottoinsieme minimale di attributi, tale che non
possono esistere più tuple con valori uguali in quegli attributi.
Esempio:
Nella relazione conto-corrente di sopra la chiave è {numero c.c.} perché non possono
esistere due correntisti con lo stesso numero di conto.
Esempio:
Nella seguente relazione con informazioni ferroviarie avente schema:
( TRENI, (binario, ora-partenza, ora-arrivo, destinazione) )
la chiave è {binario, ora-partenza} perché da un binario in una certa ora può partire
uno ed un solo treno.
6.2 Operazioni su basi di dati relazionali
Una base di dati relazionale si definisce fornendone lo schema, si popola inserendone le tuple e si
consulta applicando opportune operazioni. Le principali operazioni su relazioni sono:
Selezione
Unarie
Proiezione
Operazioni
Join
Binarie
Unione
Differenza
Le operazioni unarie si applicano ad una sola relazione e producono come risultato una nuova
relazione. Le operazioni binarie si applicano a due relazioni e producono come risultato una nuova
relazione.
SELEZIONE
L’operazione di selezione si denota con
pR
dove:
-  è il simbolo della selezione;
-
R è la relazione argomento;
-
p è un insieme di vincoli detto predicato.
e costruisce una relazione costituita dalle tuple di R che soddisfano p.
Esempio:
Si consideri la relazione R:
A
B
C
D
1
a
2
a
2
b
2
f
3
a
4
g
4
b
3
b
Se il predicato è p = {A < C} ne segue che pR dà come risultato la relazione:
A
B
C
D
1
a
2
a
3
a
4
g
Se invece il predicato è p = {B = b AND C = 2} allora pR dà come risultato:
A
B
C
D
2
b
2
f
PROIEZIONE
L’operazione di proiezione si denota con LR dove:
-  è il simbolo della proiezione;
- R è la relazione argomento;
- L è un sottoinsieme degli attributi di R.
e costruisce una relazione che comprende i soli attributi di L con le relative tuple.
Esempio:
Si consideri la relazione R:
A
B
C
D
1
a
2
a
2
b
2
f
3
a
4
g
4
b
3
b
Se è L = {A B} ne segue che ABR dà come risultato la relazione:
A
B
1
a
2
b
3
a
4
b
Se è L = {D A C} ne segue che LR da come risultato:
A
C
D
1
2
a
2
2
f
3
4
g
4
3
b
JOIN
L’operazione di join si denota con R ⋈p S dove:
- ⋈ è il simbolo di join;
- R e S sono le due relazioni argomento;
- p è un insieme di vincoli.
e costruisce una relazione ottenuta concatenando le tuple di R e S che soddisfano p.
Esempio:
Si considerino le relazioni:
R
S
A
B
C
D
E
1
a
2
a
1
2
b
2
f
2
3
a
4
b
3
4
b
5
Se è p = {C = E} ne segue che R ⋈C=E S dà come risultato la relazione:
A
B
C
D
E
1
a
2
f
2
2
b
2
f
2
Se è p = {C = E AND A = 1} ne segue che R ⋈P S dà come risultato:
A
B
C
D
E
1
a
2
f
2
UNIONE
L’operazione di unione si denota con R ∪ S dove:
- ∪ è il simbolo dell’unione;
- R e S sono le relazioni argomento.
e costruisce una relazione costituita dall’unione insiemistica delle tuple di R e S.
Osservazione: Per poter applicare la relazione di unione alle relazioni R e S, queste ultime devono
essere compatibili, ossia avere lo stesso numero di attributi definiti sugli stessi
domini di valori.
Esempio:
Si considerino le due relazioni compatibili:
R
S
A
B
C
D
E
F
1
a
2
1
a
2
2
b
2
2
b
3
3
a
4
3
a
1
4
b
3
4
b
3
L’operazione R ∪ S dà come risultato:
Osservazione:
A
B
C
1
a
2
2
b
2
3
a
4
4
b
3
2
b
3
3
a
1
Per convenzione nell’unione si prende lo schema di attributi di una delle relazioni
argomento (nell’esempio si è scelto quello di R cioè’ ABC’).
DIFFERENZA
L’operazione di differenza si denota con R – S dove:
- – è il simbolo della differenza;
- R e S sono le relazioni argomento.
e costruisce una relazione data dalla differenza insiemistica delle tuple di R e S.
Come per l’unione, anche per applicare l’operazione di differenza le relazioni
Osservazione:
argomento devono essere compatibili.
Esempio:
Si considerino le due relazioni:
R
S
A
B
C
D
E
F
1
a
2
1
a
2
2
b
2
2
b
3
3
a
4
3
a
1
4
b
3
4
b
3
L’operazione R – S dà come risultato:
A
B
C
2
b
2
3
a
4
Osservazione: Si noti che la differenza non è commutativa (R – S ≠ S – R), infatti l’operazione
S – R nell’ esempio precedente dà come risultato:
A
B
C
2
b
3
3
a
1
7. Il sistema operativo
Il sistema operativo ha una architettura software cosiddetta “a buccia di cipolla” in quanto costituita
da una serie di strati software ognuno dei quali realizza un determinato insieme di funzionalità.
Questi strati (dal basso verso l’alto) sono: nucleo, gestore della memoria, gestore delle periferiche,
file system e interprete dei comandi.
NUCLEO
Il nucleo è lo strato software del sistema operativo che gestisce i processi.
- Il programma è un oggetto statico perché resta invariato nel tempo;
- Il processo è un oggetto dinamico perché cambia nel tempo.
Definizione: Un processo è una coppia (E, S) dove E è il codice eseguibile del processo
(tipicamente il programma target prodotto dalla compilazione del corrispondente
programma) e S è l’insieme dei valori contenuti in RAM e nei registri della CPU.
Se ci troviamo in un sistema informatico a più processi si ha che, in ogni istante, un processo può
trovarsi in uno dei seguenti stati:
- In esecuzione, ossia il processo sta venendo eseguito dalla CPU;
- In attesa, ossia il processo attende che termini un’operazione di input/output;
- In pronto, ossia il processo si trova in memoria centrale pronto per essere eseguito.
L’interruzione è un meccanismo che sospende l’esecuzione di un processo quando questo richiede
ad esempio un’operazione di input/output che coinvolge una periferica (che tipicamente richiede
tempo). Nel frattempo quel processo passa in stato d’attesa e la CPU è assegnata a un altro
processo. Quando la periferica ha completato l’operazione di input/output, quel processo va in stato
di pronto, e a questo punto il nucleo gestisce il ripristino dei processi (cioè seleziona dalla coda dei
processi pronti quello che passa in esecuzione). Le politiche con cui si ripristinano i processi sono
molte, tra queste:
- FIFO (first in first out) i processi vengono eseguiti in ordine di arrivo, cioè il primo
arrivato nella coda dei processi pronti è il primo ad essere eseguito;
- PRIORITA’, i processi vengono eseguiti in base alla loro priorità, ossia ad ogni
processo viene associato un valore che ne determina l’ordine di esecuzione. Le priorità
possono essere “interne”, come il limite di tempo entro il quale il programma eseguito
deve restituire la soluzione al problema iniziale, il numero di file aperti, la lunghezza
media di operazioni di input/output e la lunghezza media delle operazioni riguardanti la
CPU, oppure “esterne”, come l’importanza del programma, il tipo e la quantità dei fondi
pagati per l’uso del calcolatore da parte dei proprietari del programma, etc.
E’ compito del nucleo del sistema operativo gestire questa alternanza fra i processi in termini di
una quanto più possibile equa rotazione.
GESTORE DELLA MEMORIA
Il gestore della memoria è lo strato software del sistema operativo che si occupa della gestione e
della suddivisione della memoria centrale (ossia come ripartire la memoria centrale tra i vari
programmi da eseguire).
Le principali problematiche del gestore della memoria riguardano:
- l’allocazione ossia:
o tecniche per suddividere la memoria;
o assegnamento di porzioni della memoria a programmi.
- la rilocazione ossia la trasformazione degli indirizzi logici presenti nel programma in
indirizzi fisici corrispondenti alla locazione di memoria dove le istruzioni sono
effettivamente caricate.
I due principali meccanismi di allocazione della memoria sono:
- la segmentazione in cui la memoria viene suddivisa in blocchi di lunghezza variabile
detti segmenti;
- la paginazione in cui la memoria viene suddivisa in blocchi di lunghezza fissa detti
pagine.
Nel suddividere e assegnare la memoria, il gestore della memoria deve attuare la miglior politica
possibile di gestione evitando la frammentazione, e garantendo sempre che le istruzioni eseguite
siano in memoria centrale.
GESTORE DELLE PERIFIRICHE
Il gestore delle periferiche è lo strato software del sistema operativo che gestisce le unità periferiche
e mette a disposizione dell’utente una serie di funzioni per eseguire operazioni di input/output
nascondendone le caratteristiche hardware. In questo modo, nei sistemi multi utente, grazie al
gestore delle periferiche, l’utente ha l’impressione di avere le periferiche totalmente dedicate a lui.
Un esempio di funzionalità del gestore delle periferiche è lo spooling system che gestisce le
molteplici richieste di stampa provenienti da vari utenti. Lo spooling system accoda le varie
richieste una dopo l’altra facendo in modo che le stampe degli utenti vengano prodotte
compiutamente, senza sovrapposizioni.
FILE SYSTEM
Il file system è lo strato software del sistema operativo responsabile della gestione dei file in
memoria di massa e consente a un utente di :
- creare un file;
- dargli un nome;
- collocarlo in memoria di massa;
- accedervi in lettura o scrittura;
Queste operazioni sono possibili grazie a comandi che nascondono all’utente la struttura interna.
I file sono inclusi in strutture chiamate directory, che sono organizzate ad albero (ogni directory può
contenere a sua voltadirectory o file). L’intero file system è organizzato ad albero:
ROOT
BIN
DEV …… USR
MARIO
F1
F2
UGO
PIERO
D1
F3
F4
INTERPRETE DEI COMANDI
L’interprete dei comandi è lo strato più alto del sistema operativo responsabile di ricevere e
interpretare i comandi dell’utente.
Questi comandi richiamano funzioni di strati più bassi del sistema operativo oppure mandano in
esecuzione programmi utente o programmi di sistema. Tra le funzioni dell’interprete dei comandi vi
è anche l’inizializzazione del calcolatore.
Esempio:
Un utente manda in esecuzione un certo programma P. L’interprete, per attivare P,
svolge trasparentemente all’utente le seguenti operazioni:
- accede al programma (che si trova nella memoria di massa) tramite il file
system;
- alloca memoria e carica il programma nella RAM tramite il gestore della
memoria;
- attiva un processo tramite il nucleo ed esegue P.
ARCHITETTURA DI UN SISTEMA INFORMATICO
8. Alberi, Alberi Binari e Algoritmi di visita
** (solo per studenti DM 509) **
Molte informazioni sono strutturate in modo gerarchico, cioè l’informazione principale comprende
informazioni di livelli successivamente inferiori fino al raggiungimento di informazioni elementari
da cui non dipende nessun’altra informazione. Come esempi, si pensi all’organigramma di
un’azienda, all’albero genealogico di una stirpe, alla descrizione di una fattura commerciale, etc.
La struttura dati Albero per memorizzare informazioni nei programmi è così definita:
Definizione:
Dato un insieme prefissato E di elementi:
- un albero può essere vuoto, ossia non contenere elementi
- un albero non vuoto può consistere di un solo elemento e in E detto nodo oppure può consistere di
un nodo e in E collegato mediante archi a un numero finito di altri alberi
La precedente definizione è ricorsiva, e sostanzialmente definisce un albero come un insieme di
nodi (dove ci sono le informazioni) collegati mediante archi. Gli alberi si rappresentano
graficamente attraverso un insieme di cerchietti (nodi) collegati gerarchicamente da linee (archi).
Esempio di albero:
Terminologia:
- Radice. E’ il nodo che non ha archi entranti (tipicamente viene disegnato in alto)
- Foglie. Sono i nodi terminali, ossia che non hanno archi uscenti
- Nodi interni. Sono i nodi che non sono radice o foglie
- Padre/Figlio. Se c’è un arco che va dal nodo a al nodo b, allora a è padre di b, e b è figlio di a
- Cammino. Un cammino dal nodo a al nodo b è una sequenza di archi contigui da a a b. La
lunghezza del cammino è il numero di archi che lo compongono (cioè il numero di nodi toccati
meno 1)
- Livello (di un nodo). E’ la lunghezza del cammino che va dalla radice a quel nodo
- Profondità o Altezza (di un albero). E’ la lunghezza del cammino più lungo che va dalla radice a
una foglia
- Sottoalbero. E’ un sottinsieme dei nodi dell’albero collegati da archi tale che è a sua volta un
albero
Nel seguito ci restringiamo a un caso particolare di alberi chiamati alberi binari e cosi definiti:
Definizione:
Un albero binario è un albero in cui ogni nodo ha al più due figli.
Per gli alberi binari esistono i concetti (intuitivamente riscontrabili nella rappresentazione grafica)
di figlio sinistro, figlio destro, sottoalbero sinistro, sottoalbero destro.
Per esempio, il seguente albero (dove per semplicità nei nodi sono state inserite informazioni
numeriche) è un albero binario, in cui, ad esempio, 8 è figlio sinistro di 9, e 5 è figlio destro della
radice 7:
7
9
5
8
8.1
Algoritmi di visita su alberi binari
“Visitare” un albero binario significa esaminare tutti i suoi elementi, toccandoli una e una sola
volta. Esistono vari modi per visitare un albero binario che variano a seconda dell’ordine in cui si
toccano i suoi nodi; per esempio un metodo è quello della visita simmetrica (anche detta in
preordine sinistro) che effettua la visita secondo lo schema ricorsivo:
radice - sottoalbero sinistro - sottoalbero destro
nel senso che questa visita tocca prima la radice, poi tutti i nodi nel sottoalbero sinistro (sempre
ricorsivamente usando lo stesso schema), e poi tutti i nodi nel sottoalbero destro (sempre
ricorsivamente usando lo stesso schema). Ad esempio, per l’albero binario disegnato nell’esempio
della sezione precedente, l’ordine di visita simmetrica dei suoi nodi è: 7 9 8 5
Di seguito elenchiamo tutti i possibili metodi di visita con il corrispondente ordine di visita:
Visita Simmetrica/in Preordine Sinistro:
radice - sottoalbero sinistro - sottoalbero destro
Visita Anticipata:
sottoalbero sinistro - radice - sottoalbero destro
Visita Posticipata:
sottoalbero destro - radice - sottoalbero sinistro
Visita in Preordine Destro:
radice - sottoalbero destro - sottoalbero sinistro
Visita in Postordine Destro:
sottoalbero destro - sottoalbero sinistro – radice
Visita in Postordine Sinistro:
sottoalbero sinistro - sottoalbero destro – radice
Vediamo alcuni esempi. Per l’albero binario disegnato nella sezione precedente, la visita simmetrica
tocca i nodi nell’ordine 7 9 8 5; la visita anticipata tocca i nodi nell’ordine 8 9 7 5; la visita
posticipata tocca i nodi nell’ordine 5 7 9 8; e così via per gli altri metodi.
Per ogni metodo di visita può essere scritto un algoritmo che ne implementa la corrispondente
strategia di visita. Di seguito riportiamo i vari algoritmi di visita. Sia A un albero binario:
Algoritmo Visita Simmetrica (A)
BEGIN
IF A non è vuoto THEN
BEGIN
RETURN radice(A)
RETURN Visita Simmetrica (sottoalbero sinistro di A)
RETURN Visita Simmetrica (sottoalbero destro di A)
END
END
Algoritmo Visita Anticipata (A)
BEGIN
IF A non è vuoto THEN
BEGIN
RETURN Visita Anticipata (sottoalbero sinistro di A)
RETURN radice(A)
RETURN Visita Anticipata (sottoalbero destro di A)
END
END
Algoritmo Visita Posticipata (A)
BEGIN
IF A non è vuoto THEN
BEGIN
RETURN Visita Posticipata (sottoalbero destro di A)
RETURN radice(A)
RETURN Visita Posticipata (sottoalbero sinistro di A)
END
END
Algoritmo Visita PreordineDestro (A)
BEGIN
IF A non è vuoto THEN
BEGIN
RETURN radice(A)
RETURN Visita PreordineDestro (sottoalbero destro di A)
RETURN Visita PreordineDestro (sottoalbero sinistro di A)
END
END
Algoritmo Visita PostordineDestro (A)
BEGIN
IF A non è vuoto THEN
BEGIN
RETURN Visita PostordineDestro (sottoalbero destro di A)
RETURN Visita PostordineDestro (sottoalbero sinistro di A)
RETURN radice(A)
END
END
Algoritmo Visita PostordineSinistro (A)
BEGIN
IF A non è vuoto THEN
BEGIN
RETURN Visita PostordineSinistro (sottoalbero sinistro di A)
RETURN Visita PostordineSinistro (sottoalbero destro di A)
RETURN radice(A)
END
END