Fondamenti Logici e Metodologici

annuncio pubblicitario
FONDAMENTI LOGICI E METODOLOGICI
INTRODUZIONE
I seguenti appunti, più che una vera e propria dispensa, sono
delucidazioni ed approfondimenti riguardanti le numerose slide con
cui vengono spiegati gli argomenti trattati in questa parte del
Corso di Informatica, concernente i FONDAMENTI LOGICI E METODOLOGICI (per
brevità FLM) della materia.
Le slide sono tendenzialmente autoesplicative ma presuppongono
almeno un minimo di spiegazione, cosa che viene riservata per le
lezioni in aula e/o in laboratorio ove, tra l’altro, saranno
svolti parecchi esempi ed esercitazioni.
Alcuni concetti di base, qui necessariamente solo introdotti,
sono ripresi ed approfonditi in apposite dispense, in particolare:
 per
un’introduzione
all’informatica
(nozione
di
Bit,
Codifica Binaria dell’Informazione, Memoria e altre nozioni
di base) si veda la dispensa Informazioni e Macchine;
 per
un’introduzione
agli
elaboratori
(schemi
logicofunzionali, componenti interni e periferici, principi di
funzionamento e architetture base) si veda la dispensa Unità
di Governo Programmabili(1) ed eventualmente Sistemi di
Numerazione.
 per i concetti di Informazione, Dato, Tipo di Dato,
Struttura Informativa e le questioni concernenti la visione
astratta e concreta dei dati, si veda la dispensa Dati(1).
Inoltre,
nell’apposita
dispensa
FLM-Esercitazioni
sono
chiaramente esemplificati diversi concetti per fissare bene le
nozioni di base riguardanti la programmazione.
La sezione Complementi riporta, in breve, alcune informazioni
utili riguardanti il variegato mondo ICT (Information and
Communication Technology).
Sono altresì disponibili corsi, esempi ed esercitazioni per i
linguaggi C/C++ e Visual Basic.
Iniziare con le slide da FLM01 a FLM12a.
prof. Felice Zampini
Fondamenti Logici e Metodologici
1/34
LINGUAGGI DI PROGRAMMAZIONE
Slide FLM13 e FLM14.
Si premettono alcune definizioni circa i linguaggi.
LINGUAGGIO: insieme finito dei simboli (alfabeto) e delle
regole per associarli (grammatica o sintassi: regole di produzione
che consentono di ottenere tutte e sole le frasi del linguaggio)
in modo significativo (semantica: regole di assegnazione dei
significati alle frasi del linguaggio) ai fini di una qualsiasi
comunicazione.
LINGUAGGIO
scopi.
ARTIFICIALE:
linguaggio
definito
per
determinati
LINGUAGGIO FORMALE O SIMBOLICO: insieme di stringhe, costituite
da caratteri o simboli di un dato alfabeto, definite mediante
regole formali di generazione (grammatica) o algoritmi di analisi
e riconoscimento.
LINGUAGGIO DI PROGRAMMAZIONE: linguaggio artificiale
codificare un algoritmo in una sequenza di proposizioni.
per
LINGUAGGIO PROCEDURALE: linguaggio programmativo in cui le
istruzioni corrispondenti alla risoluzione di un problema devono
essere eseguite in modo ordinato (linguaggio algoritmico).
LINGUAGGIO PROCEDURALE STRUTTURATO: linguaggio programmativo
che impone i costrutti della programmazione strutturata (sequenzaalternativa-selezione), di norma escludendo i trasferimenti di
controllo all'interno di un modulo di programma.
LINGUAGGIO NON PROCEDURALE: linguaggio in cui gli obiettivi da
conseguire tramite il programma sono descritti senza specificare
il relativo algoritmo risolvente (linguaggio non algoritmico: è
richiesta solo la specifica del "cosa" fare senza richiedere il
"come" farlo).
Linguaggio Macchina (linguaggi di 1a generazione)
Il linguaggio macchina (chiamato anche Linguaggio Assoluto) è quello
direttamente usato dalla macchina (CPU) e costituisce il linguaggio al
più basso livello (in quanto legato all'hardware, quindi alla specificità
del tipo di elaboratore); tale linguaggio va annoverato come linguaggio
di progettazione degli elaboratori elettronici.
Il
linguaggio
macchina
consiste
in
una
CODIFICA
BINARIA
in
corrispondenza della quale è prevista l'esecuzione di determinate
funzioni (funzioni macchina) da parte della CPU; tale codifica binaria
concerne:
-
le istruzioni macchina (codici operativi detti opcode);
-
gli operandi (indirizzi
rispettive lunghezze.
prof. Felice Zampini
fisici
di
memoria
Fondamenti Logici e Metodologici
o
dati)
nonchè
le
2/34
Linguaggio Assembler (linguaggi di 2a generazione)
Il linguaggio
codici operativi e
si rappresentano
codifica assembler
elementi:
assembler è un linguaggio di programmazione in cui i
gli indirizzi degli operandi delle istruzioni macchina
in modo simbolico (di norma codici mnemonici); la
implica dunque (almeno) la specificazione dei seguenti
-
Codici Operativi simbolici;
-
Operandi (indirizzi di memoria o dati) simbolici.
Nell'assembler, ogni proposizione del linguaggio corrisponde ad una
singola istruzione macchina, percui tale linguaggio rappresenta il
linguaggio simbolico al più basso livello (linguaggio machine-oriented).
Data
questa CORRISPONDENZA UNO-UNO TRA ISTRUZIONI ASSEMBLER ED ISTRUZIONI
il
linguaggio
assemblativo
resta
strettamente
vincolato
all'hardware,
consentendo
di
sfruttarne
le
prestazioni
in
modo
ottimizzato ma implicando, da parte del programmatore, notevoli
conoscenze
circa
l'elaboratore
utilizzato;
a
tale
vantaggio
si
contrappone lo svantaggio di una difficile "trasportabilità" dei
programmi, motivo percui la programmazione assembler è spesso utilizzata
per la realizzazione di software di base da parte di specialisti del
settore.
MACCHINA,
Linguaggio ad alto livello (HLL-High Level Language)
Un linguaggio HLL è un linguaggio programmativo in cui LA SINTASSI È
INDIPENDENTE DALLA MACCHINA; in tale linguaggio le
istruzioni vengono
espresse in forma simbolica e corrispondono in genere a più operazioni
macchina, mentre gli operandi vengono indicati non come indirizzi di
memoria ma mediante nomi simbolici (linguaggi problem-oriented).
Lo sviluppo di tali linguaggi (linguaggi di 3a generazione),
svincolando la programmazione dagli aspetti hardware (tramite i relativi
programmi traduttori) e facilitando lo sviluppo di software da parte di
utenti non specialisti (di hardware), ha anche notevolmente contribuito a
rimuovere il non trascurabile vincolo della difficile trasportabilità dei
programmi assembler.
Linguaggi di 4a generazione (4GL)
Sono linguaggi di tipo non procedurale in cui la grammatica e la
sintassi tendono ad avvicinarsi a quelle del linguaggio naturale, in modo
da facilitarne il loro impiego; si possono genericamente considerare
tali, p.es., i:
-
linguaggi conversazionali (interattività);
-
linguaggi di interrogazione e manipolazione di data bases.
Linguaggi di 5a generazione (5GL)
Sono linguaggi che ricorrono alle metodologie dell'intelligenza
artificiale, con l'obiettivo di raggiungere una interazione globale uomomacchina (istruzioni comunicate direttamente alla macchina tramite la
voce, il movimento, il tatto, ecc.).
La seguente lista elenca alcuni (fra i più comuni) degli oltre 300
linguaggi di tipo evoluto (HLL) sviluppati a livello internazionale.
prof. Felice Zampini
Fondamenti Logici e Metodologici
3/34
LINGUAGGI
SIGLA
DI TIPO
HLL
S I G N I F I C A T O
TIPO
-------------------------------------------------------------------------------ADA
A Defense Algorithm (1980)
General Purpose
ALGOL
ALGOrithmic Language (1958)
Scientif./Universale
APL
A Programming Language (1968)
Algebrico
BASIC
Beginner's All-purp. Symb. Instr. Code (1964)
Conversazionale
C
C (1972) - ANSI C (1989)
General Purpose
C++
C++ (1979) - ANSI C++ (1990)
OOP
CLOS
Common Lisp Object Oriented
OOP
COBOL
COmmon Business Oriented Language (1960)
Gestion./Commerciale
CSMP
Continuous System Modelling Program
Simulazione continua
DL/1
Data Language/1
DBMS
FORTH
Forth (1968)
4GL
FORTRAN
FORmula TRANslation (1957)
Scientifico
GOLD
Gold
CAD/CAM
GROOVE
Groove (1970)
Musicale/Interattivo
HTML
HyperText Markup Language (1995)
Grafico (Internet)
JAVA
Java (1996)
Animazione (Internet)
LIFER
Lifer
AI/ES
LISP
LISt Processor (1958)
Scientifico/Robotico
LOGO
Logo (1967)
Education
MODULA 2
Modula 2
Scientif./Gestionale
MUSIC V
Music V (1969)
Musicale
NATURAL
Natural
DBMS
PASCAL
Pascal (1968) - ANSI Pascal (1973)
Scientif./Gestionale
PL/1
Programming Language/1 (1965)
General Purpose
POP-2
Pop-2
HLL/AI
PROLOG
PROgramming in LOGic (1977)
Logica/AI
RPG
Report Program Generator (1962)
Gestionale
SEQUEL
Sructured English Query Language
DBMS
SIMULA
Simula
Simulazione discreta
SMALLTALK
Smalltalk
OOP
SNOBOL
StriNg Oriented symBOlic Language (1963)
WP
VIS. BASIC
Visual Basic
Visuale
VISUAL C++
Visual C++
Visuale
VRML
Virtual Reality Modeling Language (1995)
Realtà Virtuale
prof. Felice Zampini
Fondamenti Logici e Metodologici
4/34
COMUNICAZIONE CON LA MACCHINA
MACCHINE E LINGUAGGI
Per programmare un elaboratore occorre disporre di un
linguaggio di programmazione: un linguaggio di programmazione è un
linguaggio formale o simbolico in cui sono definiti: ALFABETO,
GRAMMATICA LESSICALE, GRAMMATICA STRUTTURALE (slide FLM15).
Dato l’alfabeto di un linguaggio di programmazione, dal punto
di vista lessicale gli elementi primitivi (TOKEN) che intervengono
nella stesura di un programma (codifica) sono in genere:
- Parole riservate (keywords)
- Identificatori
- Segni di punteggiatura e caratteri speciali
- Operatori
- Costanti numeriche e letterali
- Commenti.
Tramite questi elementi si possono formare, rispettando la
sintassi e la semantica del linguaggio, ESPRESSIONI più o meno
complesse per definire le elaborazioni da svolgere, scrivendo il
PROGRAMMA SORGENTE.
Come visto (slide FLM06, FLM07, FLM08), l’attività di
programmazione coinvolge 2 soggetti che concorrono per la
Risoluzione del problema (ben formulato) e per la Computazione
della soluzione: RISOLUTORE ed ESECUTORE AUTOMATICO; nell’ambito di tale
attività si possono distinguere fasi diverse, quindi individuare
diversi AMBIENTI: Ambiente del Problema, Ambiente dell’Analisi,
Ambiente di Elaborazione.
Siccome un programma ha lo scopo di risolvere un qualche
problema, affidandone la esecuzione ad un elaboratore, esso deve
prevedere:
 la corretta gestione delle azioni da svolgere (FLUSSI);
 la specificazione delle azioni da svolgere (ISTRUZIONI);
 la specificazione degli oggetti su cui operare (DATI).
La gestione dei flussi si realizza tramite le STRUTTURE DI
CONTROLLO della programmazione (di cui le basilari sono: sequenza,
alternativa, iterazione).
Le istruzioni costituiscono le PAROLE RISERVATE del linguaggio di
programmazione (keywords, parole cui sono associati precisi
significati operativi).
Slide da FLM16 a FLM20.
prof. Felice Zampini
Fondamenti Logici e Metodologici
5/34
I dati devono essere specificati nel programma, assegnando loro
dei nomi (IDENTIFICATORI) e degli attributi (SPECIFICATORI DI TIPO),
rispettando le regole del linguaggio, tramite apposite espressioni
chiamate DICHIARAZIONI; i dati devono inoltre poter essere definiti
ed elaborati ed a ciò si provvede con l’operazione di ASSEGNAZIONE.
Dal punto di vista logico un Dato è un’informazione codificata,
significativa,
interpretabile
e
comunicabile
cui
possiamo
associare un nome per identificarlo; introducendo una distinzione
dei dati in base al loro contenuto (ciò che essi rappresentano) ed
alle operazioni su di essi definibili (algebra associata) si
perviene al concetto di TIPO DI DATO.
Dal punto di vista concreto, fisico (implementazioni EDP) un
Dato (più in generale un Oggetto) viene riguardato come una AREA DI
MEMORIA in cui si possono memorizzare dei valori; ad un dato restano
associati NOME - TIPO - VALORE dal punto di vista logico (programma),
cui corrispondono INDIRIZZO - SPAZIO E CODIFICA - CONTENUTO BINARIO dal
punto di vista fisico (memoria).
COMPILE - LINK – GO
Slide FLM21 e FLM22.
Per comunicare con un elaboratore, al fine di fargli eseguire
un algoritmo (più in generale un programma) in forma di PROGRAMMA
ESEGUIBILE, è necessario che il programma sia portato nella sua
MEMORIA CENTRALE, infatti l’elaboratore deve farsi una RAPPRESENTAZIONE
INTERNA delle informazioni, pertanto occorre che il programma
risieda in memoria in FORMATO MACCHINA.
Un Programma Sorgente, creato con un editor ed espresso in un
linguaggio simbolico secondo le regole sintattiche e semantiche di
un dato linguaggio di programmazione, per essere trasformato in
linguaggio macchina, in modo che sia fruibile dall’elaboratore per
poter essere eseguito, deve essere trattato secondo le seguenti
fasi (cosiddetta PROCEDURA COMPILE-LINK-GO):
 Compilazione (compile): fase in cui, tramite un apposito
programma compilatore, si trasforma il programma sorgente
generando il PROGRAMMA OGGETTO o Codice Rilocabile, cioè il
programma in linguaggio macchina ma ancora in una forma
intermedia in genere non effettivamente eseguibile;
 Correlazione (link): fase in cui, tramite un apposito
programma correlatore (linker), si trasforma il codice
oggetto in PROGRAMMA ESEGUIBILE, risolvendo i Collegamenti
Esterni del programma (moduli di librerie utente o di
sistema, variabili esterne, ecc.);
 Caricamento (load): fase in cui, tramite un apposito
programma caricatore (loader), si trasforma il programma
eseguibile, i cui indirizzi sono logici e non fisici, in
PROGRAMMA CARICABILE (Codice Assoluto) o comunque si effettua il
caricamento del codice eseguibile in memoria centrale
(rilocazione dinamica) per l’effettiva esecuzione (Go o Run).
prof. Felice Zampini
Fondamenti Logici e Metodologici
6/34
IL PROGRAMMA E L’AREA DATI
La considerazione che in un programma sono presenti istruzioni
e dati porta a fare una distinzione, logica ma anche fisica, tra
due specifiche aree di memoria concernenti il programma:
 area istruzioni: area riservata alle istruzioni del programma
(linguaggio macchina) in quanto tali;
 area dati: area riservata ai dati dichiarati nel programma ed
allocati in memoria, area che sarà fissa o variabile, di
durata statica o dinamica in funzione delle dichiarazioni e
delle proprietà attribuite agli identificatori (tipo, classe
di memorizzazione, durata, visibilità, ecc.).
IL PROGRAMMA E LA CPU
Un elaboratore, visto come sistema, è inquadrabile come un
AUTOMA PROGRAMMABILE SEQUENZIALE DISCRETO, ovvero come una macchina
automatica (cioè che una volta avviata è in grado di eseguire
compiti automaticamente) programmabile (cioè che funziona in base
ad un programma fornito dall’esterno) che produce un’uscita in
funzione degli ingressi (dati), dello stato e delle istruzioni di
un programma attivo in memoria (assimilabile comunque a stato).
La macchina funziona eseguendo nel tempo operazioni in modo
sequenziale (cioè una alla volta) facendo agire un hardware se, in
dipendenza di certe cadenze temporali (tempo discreto, determinato
dagli impulsi di clock), arriva una istruzione (che determina
l’avanzamento di stato); in prima approssimazione, si può pertanto
considerare che la CPU esegue in modo sequenziale le istruzioni
del programma.
Giova comunque osservare che esistono sistemi di elaborazione
dati (SED) in grado di eseguire più istruzioni simultaneamente e
su più dati (macchine MIMD - Multiple Instruction Stream Multiple
Data Stream).
prof. Felice Zampini
Fondamenti Logici e Metodologici
7/34
PARADIGMI DI PROGRAMMAZIONE
PROGRAMMAZIONE
Slide FLM23.
Un PROGRAMMA è uno Schema Logico, un Modello, uno Schema di
Comportamento, un Algoritmo per risolvere un problema.
Un programma non è dunque, come comunemente si può ritenere, un
"insieme di istruzioni" di un dato linguaggio di programmazione,
istruzioni
che
opportunamente
trasferite
ad
un
Esecutore
Automatico (elaboratore) determineranno le Azioni da questo
effettuate
per
calcolare
la
soluzione
di
un
problema:
l'espressione
di
un
programma
tramite
un
linguaggio
di
programmazione (linguaggio formalizzato) non è che la traduzione
all'esecutore del programma, cioè la CODIFICA, la quale costituisce
un aspetto tecnico del programma, in quanto attività successiva e
determinata dal programma stesso.
PROGRAMMA
Schema logico di costruzione di regole per la
risoluzione di un problema.
La PROGRAMMAZIONE, in generale, è un'attività di Risoluzione di
Problemi, la cui esecuzione è poi affidata ad un esecutore
(automatico); la programmazione, in un contesto EDP, individua
quale esecutore un automa digitale (elaboratore) che garantisca la
effettiva Computabilità, quindi il calcolo della soluzione, di un
problema.
La programmazione, di per sè, può esprimersi tramite un
linguaggio
o
un
meta-linguaggio
(linguaggio
di
progetto,
pseudocodifica, DaB, NLS, GNS, ecc.); in un secondo momento, a
seconda della determinazione delle risorse e delle funzioni
attribuite all'esecutore, si individua l'effettivo Linguaggio di
Programmazione per tradurre all'esecutore la risoluzione del
problema.
PROGRAMMAZIONE
Attività di risoluzione di problemi la cui
computazione è affidata ad un esecutore automatico.
prof. Felice Zampini
Fondamenti Logici e Metodologici
8/34
Un programma è un prodotto industriale e come tale ha un suo
Ciclo di Vita ed un mercato; fare un buon programma significa
pertanto disporre di METODOLOGIE di progettazione, di analisi, di
sviluppo
e
codifica
dei
programmi
che
nel
loro
insieme
garantiscano la produzione di un prodotto rispondente a requisiti
di qualità ed economicità, in particolare un prodotto cui
corrisponda un buon rapporto prezzo/prestazioni.
Due fattori fondamentali, tra di loro in correlazione, hanno
posto in modo pressante l'esigenza di fare dei buoni programmi: il
costante ABBATTIMENTO DEI COSTI HARDWARE ed il conseguente SVILUPPO DEI
LINGUAGGI HLL (High Level Language), quindi del software in generale,
come esemplificato nei seguenti semplici diagrammi.
Una specifica branca della moderna informatica, che va sotto il
nome di INGEGNERIA DEL SOFTWARE, si occupa più da vicino degli aspetti
inerenti le tecnologie e le metodologie di produzione del
software, riguardondoli e valutandoli sia sotto il profilo tecnico
che economico e sociale.
Dalla primitiva programmazione cosiddetta a "piatto di
spaghetti"
(uso
indiscriminato
del
GOTO
e
di
Switches,
destrutturazione ed illeggibilità dei programmi, crescente impiego
di risorse nella manutenzione anzichè nella produzione, ecc.) si è
passati a nuovi modi di progettare e scrivere programmi,
globalmente più razionali ed efficienti, cioè a vere e proprie
Metodologie
di
Progettazione
(metodologie
di
scelta
degli
algoritmi, delle strutture dati e della codifica per fare un
programma) e Metodologie di Analisi (metodologie di analisi del
livello di qualità di un programma).
Nell’ambito dei Paradigmi di Programmazione, ove si registrano
innovativi progressi (programmazione logica e funzionale, OOP,
intelligenza artificiale, ecc.), approfondiremo inizialmente la
PROGRAMMAZIONE IMPERATIVA, la quale ha sancito la nascita della
programmazione ed è a tuttoggi affermata ed interessante.
Nell'ambito delle Metodologie di Progettazione del Software ci
occuperemo, in particolare, della PROGRAMMAZIONE STRUTTURATA, visto il
ruolo fondamentale ed unificante che essa riveste per la logica e
la programmazione.
prof. Felice Zampini
Fondamenti Logici e Metodologici
9/34
PROGRAMMAZIONE IMPERATIVA
La Programmazione
o pure operazionale)
in
modo
completo
istruendolo, ai fini
dal programma, sul:
Imperativa (detta anche PROCEDURALE, ALGORITMICA
è una metodologia in cui occorre descrivere
ed
univoco
un
processo
all’esecutore,
del raggiungimento degli obiettivi previsti
 "cosa" deve fare (cosa si vuole);
 "come" farlo (strategia risolutiva).
Nella programmazione imperativa pertanto il PROBLEMA DEL CONTROLLO
(il "come") è a carico del programmatore, il quale, prima di
invocare l’esecuzione del programma da parte dell’esecutore, deve
aver completamente risolto il problema dal punto di vista logico,
conoscendo a priori tutti i passi che l’esecutore dovrà compiere
per fornire la soluzione.
Un programma imperativo è dunque una sequenza di istruzioni
(algoritmo risolutivo) che trasferite all’esecutore lo portano a
trasformare i dati in ingresso nei risultati voluti.
Si noti che il lavoro svolto dal risolutore dedicato alla
conoscenza della realtà del problema resta, in un certo senso,
"imprigionato" nella strategia risolutiva ed è trasferito alla
macchina solo per la semplice esecuzione (l’esecutore non
acquisisce conoscenze).
Una volta identificato l’esecutore(1) un linguaggio imperativo
deve fornire gli strumenti per poter agire sullo stato degli
oggetti, cioè:
 Operazioni (Comandi) e relativi parametri per determinarne le
condizioni di applicabilità;
 Funzioni di osservazione.
(1) Assimilandolo ad una macchina virtuale (insieme di Risorse o Oggetti e
relativo Linguaggio per gestirli) per astrazione ad un certo livello di
visibilità rispetto alle risorse reali (si identifica una scatola nera,
interessandosi più al suo comportamento che alla sua costituzione).
prof. Felice Zampini
Fondamenti Logici e Metodologici
10/34
In definitiva, i concetti alla base della programmazione
imperativa sono quelli di COMANDO e di PROCEDURA ed in tale
metodologia occorre:

Specificare l’insieme degli Oggetti chiamati in causa, sui
quali si agisce, coi loro nomi e attributi;
 DICHIARAZIONI - IDENTIFICATORI - TIPI

Specificare l’insieme
oggetti ("cosa" fare);
delle
DI
Azioni
DATI
da
compiere
sugli
 ISTRUZIONI, cioè KEYWORDS del linguaggio

Gestire i Flussi, cioè l’ordine di esecuzione delle azioni,
funzionalmente al risultato da conseguire, nonchè le
condizioni da verificare affinchè esse si succedano nel
modo voluto ("come" arrivare al risultato);
 STRUTTURE DI CONTROLLO della programmazione.
Uno dei vantaggi della programmazione imperativa, che ne
compensa in parte la scarsa flessibilità, è attualmente quello
della efficienza dei programmi: un programma imperativo infatti,
una
volta
memorizzato,
fornisce
all’esecutore
tutte
le
informazioni di controllo, consentendogli di raggiungere elevate
velocità nell’eseguire le operazioni richieste e nel fornire i
risultati voluti.
PROGRAMMAZIONE DICHIARATIVA
La programmazione dichiarativa si basa sull’idea di delegare il
problema del controllo all’esecutore, facendo concentrare il
risolutore sugli aspetti che concernono la conoscenza e la
comprensione ("cosa" si vuole) del problema. Tale approccio alla
risoluzione
dei
problemi
implica
che
gli
OGGETTI
della
programmazione dichiarativa non siano semplici dati, dovendo essi
in qualche modo contenere una base di conoscenza della realtà tale
da consentire all’esecutore di trovare una risoluzione del
problema.
In un certo senso, si può dire che nella programmazione
dichiarativa la ricerca di una strategia risolutiva di un problema
viene "programmata" nelle fasi, precedenti, relative alla sua
conoscenza e comprensione, dotando un linguaggio dichiarativo di
un MECCANISMO DI RAGIONAMENTO (motore inferenziale): occorre definire
una BASE DI DATI, corretta e sufficientemente ricca di informazioni
(descrizioni di oggetti, fatti e relazioni), tale da specificare
adeguatamente la realtà e consentire di costruire una BASE DI FATTI
tramite
la
quale
il
meccanismo
di
ragionamento,
quindi
l’esecutore, sia in grado di trovare la risoluzione del problema.
prof. Felice Zampini
Fondamenti Logici e Metodologici
11/34
La programmazione dichiarativa, salvo casi specifici, non
fornisce le prestazioni di quella imperativa in termini di
efficienza ma ha il prezioso vantaggio della flessibilità,
svincolando notevolmente il programmatore dalle poco flessibili
logiche procedurali e consentendo una separazione tra i meccanismi
di risoluzione e le basi di conoscenza.
***
Considerati i due tipi fondamentali di programmazione,
programmazione imperativa e programmazione dichiarativa, si ha
che, in effetti, gli attuali linguaggi di programmazione ad alto
livello
sono
difficilmente
classificabili
come
puramente
imperativi o dichiarativi, ciascuno tendendo all’una o all’altra
categoria in base al suo scopo ed al grado di libertà fornito al
programmatore nel controllare il flusso delle azioni svolto
dall’esecutore (grado di proceduralità del linguaggio).
Tale fatto ha determinato lo sviluppo
programmazione, riassumibili nei seguenti:

PROGRAMMAZIONE IMPERATIVA

PROGRAMMAZIONE ORIENTATA

PROGRAMMAZIONE VISUALE

PROGRAMMAZIONE FUNZIONALE

PROGRAMMAZIONE LOGICA
prof. Felice Zampini
AGLI
di
diversi
tipi
di
OGGETTI (OOP-OBJECT ORIENTED PROGRAMMING)
Fondamenti Logici e Metodologici
12/34
PROGRAMMAZIONE STRUTTURATA
La Programmazione Strutturata (Structured Design) consiste in
un insieme di tecniche per progettare, sviluppare e codificare
programmi.
Le Metodologie di Progettazione Strutturata del Software
attualmente disponibili sono diverse, ciascuna con proprie
caratteristiche ed orientata verso determinati obiettivi, nè
mancano, per talune, varianti e contributi per successivi
perfezionamenti o affinamenti; tali metodologie sono comunque
riconducibili a tre filoni logici principali:
 La Decomposizione funzionale;
 La Progettazione basata sui flussi di dati;
 La Progettazione basata sulla struttura dei dati;
ed hanno come denominatore comune la SCOMPOSIZIONE MODULARE DEL PROBLEMA,
al fine di ottenere un design migliore, più razionale e
standardizzato del programma.
Concetti base della programmazione strutturata sono quelli di:
MODULO
RELAZIONE
TRA
INDIPENDENZA
MODULI
TRA
MODULI
Modulo
Insieme (funzionale) di istruzioni chiamato con un nome; la
scomposizione modulare deve realizzare l'indipendenza tra
moduli, massimizzando le relazioni tra componenti interne e
minimizzando
le
relazioni
tra
moduli,
basandosi
sulle
caratteristiche del modulo:
Connessione:
- per contenuto (peggiore)
- comune
- esterna
- per controllo
- di struttura
- di dati (migliore)
Coesione:
- casuale (debole)
- logica
- temporale
- comunicativa
- sequenziale
- funzionale (forte)
Altre Caratteristiche:
- semplicità
- correttezza
- aderenza
- dimensioni
- interfacciamento
- generalizzabilità
- duplicazione delle funzioni
prof. Felice Zampini
Fondamenti Logici e Metodologici
13/34
PRINCIPALI METODOLOGIE
















DI
ANALISI/PROGETTAZIONE STRUTTURATA
DEL
SOFTWARE:
GRAFI DI FLUSSO (DAB, GNS)
DIAGRAMMI SINTATTICI
NOTAZIONE LINEARE STRUTTURATA (NLS)
BOTTOM-UP
TOP-DOWN (MILLS)
JACKSON
WARNIER
WIRTH
DIJKSTRA
CONSTANTINE-YOURDON-MYERS
SSA (STRUCTURED SYSTEM ANALYSIS)
SADT (STRUCTURED ANALYSIS AND DESIGN TECHNIQUE)
HIPO (HIERARCHICAL-INPUT PROCESSING-OUTPUT)
PSL (PROGRAM STATEMENT LANGUAGE)
4GL, 5GL, DBMS
TECNICHE NON PROCEDURALI
Siccome in un programma intervengono istruzioni, dati e flussi,
si possono distinguere due tipologie fondamentali di Strutture:
 Strutture relative all'elaborazione;
 Strutture di controllo;
le prime determinano le elaborazioni, mentre le seconde governano
i flussi.
La programmazione strutturata si basa sull'uso razionalizzato
delle strutture o costrutti di controllo per realizzare programmi
strutturati
rispondenti
alle
caratteristiche
precedentemente
descritte.
Poniamo le seguenti definizioni:

Un programma si dice proprio se ha un solo punto di inizio
ed un solo punto di fine;

Due programmi si dicono equivalenti (più precisamente
fortemente equivalenti) se sottoposti agli stessi dati di
ingresso o non terminano o terminano producendo gli stessi
effetti;

Un insieme di strutture di controllo si dice completo se
esse sono sufficienti a rappresentare qualunque algoritmo
ammesso (di conseguenza, ogni programma potrà essere
rappresentato con un programma equivalente che utilizzi i
soli costrutti appartenenti a tale insieme).
A questo punto, il problema fondamentale della programmazione
strutturata può formularsi come segue:
prof. Felice Zampini
Fondamenti Logici e Metodologici
14/34
esiste un insieme completo di strutture di controllo che
non limiti il potere espressivo degli algoritmi ammessi?
La risposta a tale interrogativo è positiva ed è data dal
seguente teorema.
TEOREMA DELLE STRUTTURE (BÖHM-JACOPINI 1966)
Le Strutture di Controllo
SEQUENZA ALTERNATIVA ITERAZIONE
costituiscono un Insieme Completo
Il teorema afferma che i costrutti di controllo Sequenza,
Alternativa, Iterazione sono sufficienti a rappresentare un
programma equivalente a qualsiasi altro, dal punto di vista dei
processi generati, per qualsiasi valore dei dati in ingresso, cioè
che, in particolare, dato un programma esiste sempre un programma
strutturato equivalente, ovvero che dà luogo alla stessa sequenza
di azioni, per ogni combinazione dei dati in ingresso.
In altri termini ancora, un programma proprio può essere
risolto con i soli tre tipi di strutture di controllo Sequenza,
Alternativa e Iterazione (quindi - vedi pure COMUNICAZIONE DI DIJKSTRA
- non indispensabilità, inutilità o addirittura dannosità, di
altre strutture), percui la programmazione strutturata non limita
il potere espressivo degli algoritmi.
Le strutture di controllo SEQUENZA - ALTERNATIVA - ITERAZIONE vengono
dunque a costituire le tre STRUTTURE BASE DI CONTROLLO della
programmazione strutturata, tuttavia, per la migliore leggibilità
del
programma
e
per
una
maggiore
naturalezza
delle
rappresentazioni, è spesso conveniente affiancare tali costrutti
con altri costrutti ausiliari (generalmente implementati nei
moderni linguaggi di programmazione ad alto livello).
Vediamo ora di descrivere queste strutture di controllo e la
metodologia della programmazione strutturata; a tale scopo,
definite alcune regole o convenzioni, utilizzeremo le seguenti
rappresentazioni, basate su pseudo-linguaggi o meta-linguaggi più
formalizzati e strutturati dei Linguaggi di Progetto (LP) e della
Pseudocodifica generica:
 Diagrammi a blocchi strutturati (DaB);
 Notazione Lineare Strutturata (NLS);
 Grafi Nassi-Schneiderman (GNS).
Vedasi slide da FLM24 a FLM35.
prof. Felice Zampini
Fondamenti Logici e Metodologici
15/34
SOTTOPROGRAMMI
Slide FLM36.
Molte metodologie di analisi e progettazione del software, in
particolare la programmazione strutturata, si basano sulla
SCOMPOSIZIONE MODULARE DEI PROBLEMI, un programma può dunque essere
concepito come un modulo principale (main program) ed un insieme
di sottoprogrammi che, opportunamente progettati e gestiti,
facilitino e rendano più efficiente la progettazione e la codifica
del software.
Un MODULO O SOTTOPROGRAMMA consiste in una serie di istruzioni
caratterizzato dai seguenti elementi generali:
 Nome: identificatore del sottoprogramma;
 Funzione: sottoproblema che il modulo deve risolvere;
 Interfaccia: relazioni che il modulo deve avere col main
program e con gli altri moduli coi quali avviene uno scambio
di informazioni (insieme dei dati di ingresso e di uscita del
sottoprogramma); un buon interfacciamento software deve
soddisfare a criteri di indipendenza tra moduli.
La gestione di un sottoprogramma deve prevedere in generale:
 la possibilità di attivare o richiamare il sottoprogramma da
un punto qualunque di un programma o sottoprogramma (ISTRUZIONI
DI SALTO A SOTTOPROGRAMMA: si specifica il nome del sottoprogramma
chiamato o istruzioni del tipo CALL, GOSUB e simili ed
eventuali parametri);
 la sospensione del programma chiamante ed il salvataggio del
suo stato;
 il PASSAGGIO
chiamato;
DI
PARAMETRI,
se
previsto,
al
sottoprogramma
 la cessione del controllo al sottoprogramma chiamato;
 la RESTITUZIONE
chiamante;
DEI
PARAMETRI,
se
prevista,
dal
chiamato
al
 la restituzione del controllo al chiamante ed il ripristino
del suo stato, in modo che l’elaborazione possa riprendere
correttamente
(ISTRUZIONI
DI
RITORNO
DA
SOTTOPROGRAMMA:
si
specificano istruzioni del tipo EXIT, RETURN e simili).
Classificazione generale dei sottoprogrammi
 Procedurali (procedure o subroutine)
 Chiusi o esterni;
 Aperti o macroistruzioni;
 Funzionali (function).
prof. Felice Zampini
Fondamenti Logici e Metodologici
16/34
L’uso
vantaggi:
di
sottoprogrammi
consente
 eliminazione di riscritture
analoghe di istruzioni;
di
di
ottenere
sequenze
i
seguenti
sostanzialmente
 migliore modellizzazione dei problemi e possibilità di
strutturare moduli generalizzati riutilizzabili in diversi
contesti;
 virtuale
estensione
dell’insieme
dei
comandi
(tramite
procedure) e dell’insieme delle operazioni (tramite function)
del linguaggio di programmazione;
 migliore protezione delle entità che intervengono nella
programmazione (variabili locali e globali, visibilità degli
identificatori, ecc.);
 possibilità di definire librerie-utente
librerie di sistema (header file).
e
di
utilizzare
PASSAGGIO DEI PARAMETRI
Slide FLM37.
L’interfaccia di comunicazione tra moduli deve consentire la
comunicazione tra di essi, cioè il passaggio dei parametri.
Un sottoprogramma può essere senza parametri (stampa di
un’immagine d’intestazione a video, pulizia dello schermo,
produzione di un segnale acustico, ecc.) o con parametri.
In
PARAMETRI
un
sottoprogramma con parametri la corrispondenza tra
ATTUALI e PARAMETRI FORMALI deve in generale essere tale che:
- il numero dei parametri sia uguale;
- l’ordine dei parametri sia uguale;
- il tipo dei parametri sia uguale (o compatibile);
- la direzionalità dei parametri (in/out/inout) sia congrua.
Il passaggio dei parametri può avvenire secondo 2 modalità:
- passaggio per valore (o per copia);
- passaggio per indirizzo (o per riferimento).
Passaggio per Valore
I parametri attuali del programma chiamante e formali del
programma chiamato fanno riferimento a 2 ambienti (aree di
memoria) distinti ed indipendenti, ovvero le corrispondenti
variabili sono allocate in appositi spazi di memoria.
prof. Felice Zampini
Fondamenti Logici e Metodologici
17/34
Il passaggio dei parametri avviene trasferendo (copiando) il
valore contenuto nel parametro attuale del programma chiamante nel
corrispondente parametro formale del programma chiamato (variabile
del sottoprogramma), in tal caso i valori dei parametri attuali
non
vengono
modificati
dalle
operazioni
compiute
sui
corrispondenti parametri formali, attuando così una forma di
protezione dei dati del programma chiamante.
Passaggio per Indirizzo
I parametri attuali del programma chiamante e formali del
programma chiamato fanno riferimento allo stesso ambiente, ovvero
all’area di memoria in cui sono allocate le variabili del
programma chiamante.
Il passaggio dei parametri avviene passando al programma
chiamato gli indirizzi dei parametri attuali del programma
chiamante (previa valutazione ed allocazione del risultato qualora
il parametro attuale non sia una variabile semplice).
In altri termini, i riferimenti di read/write sui parametri
formali si traducono in riferimenti indiretti agli indirizzi di
essi; si noti che nel passaggio per indirizzo le modifiche
compiute
dal
programma
chiamato
sui
parametri
formali
si
riflettono sui corrispondenti parametri del programma chiamante.
Passaggio degli Array
Il problema del passaggio degli array ai sottoprogrammi,
implicando per i parametri attuali e formali considerazioni
riguardanti le dimensioni, gli indici, le lunghezze ed i tipi di
dati, viene risolto in ciascun linguaggio di programmazione in
modo opportuno. In via generale, si possono indicare due soluzioni
ai limiti, entro le quali si potrebbe adottare il criterio
migliore rispetto al contesto:
1. tra parametri attuali e formali si richiede una esatta
corrispondenza; questa soluzione presenta il vantaggio di
offrire la massima protezione dell’ambiente ma presenta la
restrizione di non poter generalizzare i sottoprogrammi, in
quanto gli array devono essere specificati con esattezza in
tutti i loro parametri (p.es. non sarebbero gestibili array
che differiscano anche per la sola lunghezza);
2. si passa soltanto l’indirizzo di memoria del primo elemento
dell’array, indipendentemente dai suoi altri attributi;
questa soluzione offre la massima flessibilità nella
gestione degli array, consentendo l’utilizzazione di array
di tipo dinamico e di conseguenza la generalizzazione dei
sottoprogrammi, così facendo viene meno però la protezione
dell’ambiente e l’esposizione al rischio di violarne
l’integrità aumenta.
prof. Felice Zampini
Fondamenti Logici e Metodologici
18/34
Osservazioni
 Un SOTTOPROGRAMMA APERTO è assimilabile ad una macrodefinizione o
macroistruzione; quando si parla di espansione locale di una
macro si intende dire che per ogni richiamo della macro
(macrorichiamo) il relativo gruppo di istruzioni va a
sostituire il macrorichiamo nel punto in cui esso compare nel
programma chiamante; siccome un sottoprogramma aperto è
incluso nel codice del main program il suo ambiente ed i suoi
simboli sono noti al compilatore e non si hanno problemi di
risoluzione dei collegamenti da parte del linker.
 Un SOTTOPROGRAMMA CHIUSO non comporta nessuna espansione nel main
ma implica la necessità della risoluzione dei links, in
quanto un richiamo ad esso nel main appare al compilatore
come un simbolo esterno; la risoluzione dei links si realizza
tramite
apposite
direttive,
definendo
opportunamente
l’etichetta della procedura come simbolo esterno nel main ed
un entry point nella procedura.
 Per quanto detto, in via approssimativa (le considerazioni da
fare dovrebbero riferirsi al contesto) si può dire che i
sottoprogrammi aperti implicano in genere la richiesta di
maggiore memoria ma potrebbero rivelarsi più veloci mentre i
sottoprogrammi chiusi richiedono meno memoria ma necessitano
di tempi maggiori per il fatto di essere procedure esterne
(maggiori tempi di chiamata e ritorno da sottoprogramma).
 In genere il ritorno da sottoprogramma causa la deallocazione
dell’ambiente riservato al sottoprogramma.
 Circa gli ambienti, gli oggetti, le dichiarazioni e gli
identificatori i diversi linguaggi consentono, a vari
livelli, diverse possibilità gestionali: ambienti (globale,
locale) e tipi di oggetti (tipi di dati) variegati,
dichiarazioni
di
riferimento
in
avanti,
classi
di
memorizzazione, campo d’azione, durata e visibilità degli
identificatori,
allocazioni
dinamiche,
definizioni
di
prototipi, ecc.
prof. Felice Zampini
Fondamenti Logici e Metodologici
19/34
RICORSIONE
Slide FLM38.
Una definizione si dice ricorsiva se viene definito qualcosa in
termini di se stesso.
Un classico esempio di definizione ricorsiva
fattoriale di un numero n (intero non negativo), n!:
è
dato
dal
n! =
 1
se n=0
 n*(n-1)!
se n>0
In base a tale definizione, il calcolo del fattoriale di un
numero si sviluppa in 2 fasi:
1. applicazione del procedimento ricorsivo cui da luogo la
formula: n=n*(n-1)! fino ad arrivare alla condizione
fissata per definizione: 0!=1 (condizioni iniziali);
2. valutazione delle espressioni ottenute per ricorsione, le
quali devono poter essere rimaste sospese, fino ad arrivare
al risultato finale.
Inizio procedimento
4!=4*3!
4*6=24

Fine valutazione

3!=3*2!
3*2=6


2!=2*1!
2*1=2


1!=1*0!
1*1=1

Condizioni iniziali 0!

=
1 Inizio valutazione
BASE RICORSIVA
prof. Felice Zampini
Fondamenti Logici e Metodologici
20/34
Una definizione ricorsiva implica di stabilire:
a) la BASE DI RICORSIONE, cioè
viene definito l’inizio
(nell’esempio: 0!=1);
le
o
condizioni iniziali, percui
chiusura della ricorsione
b) la REGOLA DI RICORRENZA, cioè la definizione del risultato (per
valori delle variabili diversi dalle condizioni iniziali)
tramite espressioni in cui si richiede il risultato stesso
ricorrendo a relazioni che richiamano se stesse, in modo da
arrivare alla chiusura della ricorsione (riduzione del
problema a problemi via via più semplici fino ad arrivare
alle condizioni iniziali; nell’esempio: n!=n(n-1)!).
Dal punto di vista algoritmo, o meglio dei sottoprogrammi
(procedurali o funzionali), un sottoprogramma è ricorsivo quando
al suo interno compare una chiamata a se stesso, cioè una
istruzione del sottoprogramma richiede una nuova esecuzione del
sottoprogramma medesimo, in tal caso si parla di ricorsione
semplice.
Si
parla
invece
di
ricorsione
indiretta
quando
il
sottoprogramma richiama se stesso attraverso chiamate ad altri
sottoprogrammi che a loro volta lo richiamano.
La considerazione che durante il procedimento ricorsivo, che
deve terminare chiudendosi sulle condizioni iniziali (base di
ricorsione), le varie chiamate originano espressioni che devono
rimanere sospese per essere poi valutate a ritroso a partire dalle
condizioni iniziali (valutazione del problema dai suoi aspetti più
semplici fino al raggiungimento del risultato) induce a fare le
seguenti osservazioni:
 occorre mantenere in memoria tutte le espressioni sospese, in
altri termini il sistema di elaborazione deve consentire la
gestione dinamica degli ambienti; in pratica, possiamo
ritenere che la ricorsione equivalga ad una ITERAZIONE
associata all’uso di uno STACK;
 la soluzione ricorsiva di un problema è senz’altro elegante
ai fini della modellizzazione del problema e della scrittura
del programma, l’esecuzione di quest’ultimo risulta però, in
genere,
piuttosto
onerosa
(in
termini
di
chiamate
procedurali, spazi di memoria richiesti, tempo di calcolo);
una soluzione ricorsiva potrebbe rivelarsi dunque, a seconda
dei contesti, globalmente non altrettanto efficiente quanto
una soluzione iterativa;
 la ricorsione poggia le sue basi sul principio di induzione
matematica.
prof. Felice Zampini
Fondamenti Logici e Metodologici
21/34
Riprendendo l’esempio del fattoriale dal punto di vista dei
sottoprogrammi, si può schematizzare una procedura ricorsiva come
nella slide FLM38, ove il sottoprogramma ricorsivo è la funzione
FATT (vedi pure gli esempi di programmazione).
Si noti che loops nidificati di costrutti iterativi simili
(while
nidificati,
repeat
until
nidificati)
equivalgono
a
costruzioni ricorsive.
Il concetto di ricorsione viene generalizzato da quello di
RICORSIONE STRUTTURALE.
Esempi di definizioni ricorsive
1)
a*n =
 0
se n=0
 a*(n-1)+a
se n>0
5*3 = 5*(2)+5 = 5*(1)+5+5 = 5*(0)+5+5+5 = 0+5+5+5 = 15
2)
an =
 1
se n=0
 a*(an-1)
se n>0
53 = 5*(52) = 5*5*(51) = 5*5*5*(50) = 5*5*5*1 = 125
3)
MCD(a,b) =
 a
se b=0
 MCD(b,amodb)
se b>0
MCD(20,12) = MCD(12,8) = MCD(8,4) = MCD(4,0) = 4
prof. Felice Zampini
Fondamenti Logici e Metodologici
22/34
RICERCA
Introduzione
La ricerca (search) è quell’operazione consistente nel trovare
una certa informazione all’interno di un dato insieme di
informazioni; la ricerca costituisce uno dei problemi fondamentali
dell’informatica,
sia
perchè
tale
operazione
è
in
genere
preliminare ad altre (inserimenti, cancellazioni, modifiche,
stampe, ecc.) sia perchè il grado di efficienza di una ricerca
garantisce una generale economia in termini di tempi, spazi e
costi nella gestione dei sistemi informativi.
Una ricerca dipende dai seguenti fattori principali:
*
organizzazione dei dati;
*
supporto di registrazione dei dati;
*
complessità o costo della ricerca.
Per quanto concerne la organizzazione dei dati le tecniche di
ricerca si differenziano a seconda che l’insieme di informazioni
sul quale effettuare una ricerca sia:
 ordinato/non ordinato;
 strutturato/non strutturato;
 dotato/non dotato di elementi
informazioni (campi chiave);
atti
ad
identificare
le
 dotato/non dotato di elementi atti a far identificare le
informazioni (indici, pointer).
Tra i casi più interessanti che coinvolgono le applicazioni di
ricerca, con riguardo all’organizzazione dei dati, possiamo
menzionare due situazioni in un certo senso agli estremi: quella
in cui l’insieme di informazioni abbia la struttura di un FILE DATI
(insieme strutturato, dotabile anche di tutti gli attributi
suddetti), ove l’informazione da individuare sarà un record, e
quella in cui l’insieme di informazioni sia un file testuale
(insieme non strutturato, scarsamente dotabile degli attributi
suddetti), ove l’informazione da individuare sarà una parola (si
pensi, p.es., alla ricerca di un vocabolo in un testo, per
effettuare il controllo ortografico).
A livello esemplificativo, si potrebbe pensare come situazione
intermedia quella relativa all’organizzazione di un dizionario
(struttura semplice e sostanzialmente testuale, necessità di un
ordinamento, buona norma utilizzare degli indici.
prof. Felice Zampini
Fondamenti Logici e Metodologici
23/34
Per quanto concerne il supporto di memorizzazione dei dati le
tecniche di ricerca si differenziano a seconda che esso sia:
 la memoria centrale, in tal caso si parla di
RICERCA INTERNA;
 una memoria ausiliaria (nastro, disco), in tal caso si parla
di RICERCA ESTERNA.
Nella ricerca in memoria centrale un insieme di record può
essere visto come una tabella, mentre nella ricerca esterna un
insieme di record può essere visto come un file dati.
Per quanto concerne la complessità (vedi seguito), le tecniche
di
ricerca
si
differenziano
a
seconda
di
una
serie
di
considerazioni, sostanzialmente legate agli aspetti riguardanti
l’organizzazione dei dati, il loro volume, la loro disposizione
iniziale, le strategie di ricerca e relative implementazioni ed il
tipo di contesto o applicazione in cui la ricerca stessa avviene.
Circa la complessità, generalmente si parla di:
 complessità degli algoritmi;
 complessità dei programmi;
 complessità in spazio;
 complessità in tempo.
Metodi Base di Ricerca Interna
Confronto per chiavi
La ricerca è condotta confrontando una data chiave (dato che si
desidera ricercare) con un’informazione (strutturalmente data, di
norma un campo chiave) contenuta in ciascun record del file, in
modo da individuare nel file la posizione relativa al record
cercato (se la ricerca è con successo).
Metodi:
- Lineare;
- Lineare su insiemi ordinati;
- Con sentinella;
- Binaria o dicotomica;
- Alberi binari di ricerca (B-tree).
Trasformazione della chiave
La ricerca è condotta introducendo una qualche elaborazione
sulla chiave, in modo da individuare nel file la posizione
relativa al record cercato (se la ricerca è con successo).
Metodi:
- Tecniche Hash.
prof. Felice Zampini
Fondamenti Logici e Metodologici
24/34
Metodi Base di Ricerca Esterna
La ricerca esterna implica una serie di considerazioni che, in
via introduttiva, riguardano sia i metodi d’accesso che le
problematiche
di
allocazione
degli
spazi
sui
supporti
di
registrazione dei dati.
La scelta di tecniche di ricerca esterna appropriate ed
efficienti, nei vari contesti, diventa un fattore cruciale
pressochè in tutte le applicazioni, essendo le memorie ausiliarie
tecnologicamente assai più lente di quelle centrali.
Diversi metodi di ricerca interna possono essere opportunamente
applicati anche per la ricerca esterna, la quale può svolgersi
secondo due metodi di base:
- Ricerca per posizione;
- Ricerca per chiave.
Ricerca per posizione
La ricerca è condotta specificando il numero d’ordine del
record da ricercare, cioè la sua posizione all’interno del file
(ciò implica la necessità di dover conoscere tale numero, rendendo
tale tipo di ricerca piuttosto impraticabile da parte dell’utente
finale).
Ricerca per chiave
La ricerca è condotta specificando il valore della chiave
corrispondente alla chiave del record da trovare; tale ricerca si
rivela più idonea nei confronti dell’utente finale, in quanto più
vicina alla visione logica dei dati e non vincolata alla
preventiva conoscenza della posizione del record nel file
(posizione che dovrà essere determinata automaticamente dal
sistema o da apposite procedure predisposte allo scopo).
Data l’importanza della ricerca esterna e lo stretto legame
esistente tra tale ricerca ed i metodi d’accesso, per ora si
svilupperà la ricerca interna, tra l’altro più semplice e
propedeutica a quella esterna, rimandando ad apposita sede
(nell’ambito dello studio dei File Dati e del File System)
l’approfondimento delle tecniche di ricerca esterna.
Esempi di algoritmi e programmi di ricerca saranno svolti in
aula ed in laboratorio.
prof. Felice Zampini
Fondamenti Logici e Metodologici
25/34
ORDINAMENTO
Introduzione
L’ordinamento
(sort)
è
quell’operazione
consistente
nel
disporre un dato insieme di informazioni secondo una data legge di
ordinamento definita su di esso.
Per l’ordinamento possono svolgersi considerazioni simili a
quelle viste per la ricerca, in particolare si parlerà di
ordinamento esterno ed interno.
Tali considerazioni saranno meglio precisate di seguito nella
trattazione specifica dei metodi di ordinamento. Per ora giova
osservare che un metodo di ordinamento esplica, su ciascun
elemento esaminato, le seguenti operazioni :
 determinazione della posizione finale dell’elemento
funzione del criterio di ordinamento considerato;
in
 spostamento dell’elemento (dato o riferimento al dato) nella
sua posizione finale.
Metodi Base di Ordinamento
Per Inserzione
- Base;
- Inserzione Diretta;
Per Selezione
- Base;
- Selezione Diretta;
Per Scambio
- Per Affioramento (bubble-sort);
- Veloce (quick-sort);
Per Fusione (merge)
- Base;
- Sort-merge binario.
Le slide FLM39 e FLM40 illustrano tramite
grafiche alcuni metodi di ordinamento.
esemplificazioni
Esempi di algoritmi e programmi di ordinamento saranno svolti
in aula ed in laboratorio.
prof. Felice Zampini
Fondamenti Logici e Metodologici
26/34
COMPLESSITÀ
Introduzione
Gran parte del lavoro degli informatici riguarda soprattutto
l’analisi e la risoluzione di problemi, in forma computabile ed
automatizzata. In tale lavoro rivestono fondamentale importanza,
in prima istanza, le scelte che si fanno in relazione a:
- Algoritmi;
- Programmi (in codice sorgente o eseguibili);
- Strutture Dati.
Per poter esprimere una qualche valutazione in merito alle
scelte suddette, quantitativa o almeno qualitativa, occorre
introdurre qualche criterio che consenta di decidere, in via
generale ed eventualmente anche in base al contesto, quali siano
le scelte migliori.
In altri termini, occorre avere almeno un orientamento per
decidere se e quando un algoritmo, un programma (sottintenderemo
in codice sorgente o eseguibile) o una struttura dati siano un
buon algoritmo, un buon programma o una buona struttura dati.
Tali scelte non sono sempre semplici e spesso conducono a dover
mediare tra elementi antitetici. In via generale, si possono
elencare una serie di requisiti idonei a descrivere talune
caratteristiche desiderabili per gli algoritmi, i programmi e le
strutture dati (per gli algoritmi e le strutture dati si rivedano
le loro definizioni e caratterizzazioni).
Requisiti generali per un buon programma:
 Efficienza: grado di impiego delle risorse(1) privilegiate del
sistema (memoria e CPU, cioè spazio e tempo);
 Flessibilità: gamma di applicazioni diverse soddisfatte dal
programma;
 Modularità:
architettura
della
decomposizione
logicofunzionale
del
programma
in
moduli
indipendenti
e
interconnessi (ottimizza la progettazione, la codifica, la
messa a punto, la manutenzione ed in generale tutto il ciclo
di vita del software);
(1)
Risorsa: entità Hw o Sw (CPU, memoria, periferica, istruzione, dato,
messaggio, ecc.) nell’EDP, componente Hw o Sw necessaria per creare o
far avanzare un processo.
prof. Felice Zampini
Fondamenti Logici e Metodologici
27/34
 Portabilità: capacità del programma di essere eseguito su SED
diversi (a costi di programmazione nulli o perlomeno esigui e
senza alterarne significativamente le prestazioni);
 Interfaccia Utente : grado di accuratezza con cui è gestita
la
comunicazione
utente-finale/macchina
(consistenza,
intuitività, interattività, GUI, data-entry controllato,
aiuti in linea, ecc.);
 Leggibilità: grado di leggibilità del codice sorgente (uso di
indentazioni o rientri per evidenziare i costrutti, di
commenti per esplicitare lo scopo delle azioni o delle
variabili, ecc.);
 Documentazione: grado di accuratezza della documentazione
inerente il programma (manuale utente, documentazione online, ecc.).
Tenendo conto della differenza tra algoritmo (schema logico) e
programma (codificato o eseguibile = insieme di istruzioni), i
requisiti sudddetti di efficienza, flessibilità, modularità,
leggibilità
e
documentazione
possono
adeguatamente
essere
applicati anche agli algoritmi.
Una FUNZIONE DI COSTO (in EDP) è una funzione che determina il
costo,
espresso
secondo
apposite
unità
di
misura
(non
necessariamente monetarie), per la gestione/elaborazione di una
risorsa (p.es. un archivio) o di un processo (p.es. un
ordinamento).
Così, per esempio, si può parlare di costo di un ordinamento in
termini di numero di operazioni (quali scansioni di elementi e
scambi di posto) necessarie per eseguire l’ordinamento di un dato
numero di elementi, oppure in termini di tempo impiegato (in un
dato contesto) per eseguire tale ordinamento.
Nel primo caso la valutazione è più pertinente per un algoritmo
mentre nel secondo caso è più pertinente per un programma in
esecuzione.
Analogamente, si può parlare di costo-uomo per la scrittura di
un programma e di costo-macchina per eseguire tale programma, in
questo caso utilizzando unità monetarie (di norma il costo-uomo è
considerevolmente superiore al costo-macchina).
Per valutare le caratteristiche e le prestazioni di algoritmi e
programmi (i quali sono comunque in stretta correlazione, essendo
un
programma
l’implementazione
di
un
algoritmo)
possiamo
introdurre
il
concetto
di
Complessità
(complessità
computazionale), intesa come misura della quantità di risorse
impiegate da un algoritmo o da un programma per la sua esecuzione.
Consegue da ciò che è lecito relazionare la Complessità di un
Problema con la complessità degli algoritmi che risolvono quel
problema.
prof. Felice Zampini
Fondamenti Logici e Metodologici
28/34
L’analisi della complessità deve essere svolta in modo da
rendere indipendenti gli algoritmi ma anche i programmi dal
particolare elaboratore (reale o virtuale) sul quale essi
potrebbbero essere implementati.
A tale scopo, occorrerà prescindere (in particolare per gli
algoritmi) da valutazioni coinvolgenti le risorse fisiche (tempi
di CPU, spazi di memoria) e cercare espressioni in grado di
esprimere la complessità basandosi sul tipo e numero di operazioni
ed eventualmente sul tipo e numero di dati chiamati in causa negli
algoritmi e nei programmi.
In altri termini, la complessità deve essere valutata in modo
generale, tramite funzioni matematiche che ne esprimano non tanto
il valore quanto l’ordine, la legge di variazione (studio di tipo
qualitativo, ed in tal senso saranno usati termini quali Tempo di
Esecuzione e simili).
Per determinare una funzione di complessità occorre individuare
quelle grandezze dalle quali questa può dipendere, tali grandezze
potrebbero essere anche molte ed influire in modo diverso, più o
meno significativamente, nel determinare la complessità.
Per esempio, si potrebbero considerare grandezze quali: il tipo
ed il numero di operazioni, la dimensione del problema (numero di
elementi da trattare), il tipo di dati, la disposizione iniziale
dei dati e via dicendo.
Si dice Parametro Rilevante per un algoritmo A o un programma P
una grandezza (opportunamente scelta) dalla quale dipende la
complessità C(A) di A o C(P) di P: C(A) e C(P) sono dunque
funzioni dei parametri rilevanti per A e per P.
Lo studio della complessità che segue è in relazione agli
Esecutori Sequenziali; gli algoritmi orientati a modelli di
esecutori paralleli saranno trattati a parte.
Complessità dei Programmi
La complessità
fattori principali:
C(P)
di
un
programma
dipende
dai
seguenti
 Struttura dell’algoritmo utilizzato
 Dimensione del problema (numerosità dei dati)
 Caratteristiche dei dati di input
 Disposizione (ordinamento)
 Attributi (tipo di dati)
 Qualità del codice generato dal traduttore
 Natura e velocità delle istruzioni macchina utilizzate.
Le funzioni di costo più interessanti per
riguardano le risorse privilegiate: memoria e CPU.
prof. Felice Zampini
Fondamenti Logici e Metodologici
valutare
C(P)
29/34
Si può dunque parlare di due tipi di complessità.
Complessità in Spazio
Esprime una misura quantitativa della memoria centrale
effettivamente occupata dal programma e dai dati su cui esso opera
durante l’esecuzione (si tenga presente che alcuni linguaggi
consentono la allocazione dinamica della memoria).
Tale misura riguarda:
 l’area istruzioni, determinata dal tipo di traduttore;
 l’area dati, determinata dai dati.
Complessità in Tempo
Esprime la legge di variazione del tempo di esecuzione del
programma in funzione dei parametri rilevanti considerati.
Essendo la complessità in tempo la funzione più interessante da
determinare, parleremo di complessità sottintendendo complessità
in tempo.
Sono
da
ritenersi
parametri
rilevanti,
ai
fini
della
determinazione della funzione di complessità in modo indipendente
dal contesto (ambiente di elaborazione: CPU, linguaggio, codifica,
ecc.), i seguenti elementi:
 Dimensione N del problema;
 Numero e tipo di operazioni rilevanti svolte dall’algoritmo
risolutore per risolvere il problema.
Possono considerarsi rilevanti, subordinatamente al contesto, i
seguenti elementi:
 Disposizione iniziale dei dati;
 Ambiente di elaborazione.
Una funzione completa per esprimere C(P) in forma generalizzata
potrebbe assumere la forma seguente:
C(N) = k*f(operazioni rilevanti algoritmo)
ove k indica una costante
globalmente il contesto.
di
proporzionalità
che
rappresenta
La stretta dipendenza della complessità dall’algoritmo rinvia
dunque
all’analisi
della
complessità
computazionale
degli
algoritmi, sostanzialmente in grado di fornire le funzioni di
complessità dei programmi a meno di fattori costanti (dipendenti
dal contesto e dalla complessità in spazio).
prof. Felice Zampini
Fondamenti Logici e Metodologici
30/34
La dimensione del problema (numerosità N dei dati) è, come
visto, un
parametro rilevante per la complessità; allo scopo di
far rientrare nell’analisi anche valutazioni concernenti aspetti
più generali dei dati (disposizione, tipo) tale analisi viene
condotta considerando le seguenti situazioni.
Caso Peggiore: è la complessità determinata in funzione della
disposizione
dei
dati
percui
l’algoritmo
ha
comportamento
peggiore. Tale caso è particolarmente interessante ai fini della
determinazione del limite superiore di complessità entro il quale
l’algoritmo opera.
Caso Medio: è la complessità determinata come media sulla base
di tutte le possibili occorrenze dei dati. Tale caso può fornire
indicazioni utili sul comportamento dell’algoritmo in generale, ma
spesso è difficile da analizzare e non sempre può avere
significato applicativo.
Caso Migliore: è la complessità determinata in funzione della
disposizione
dei
dati
percui
l’algoritmo
ha
comportamento
migliore. Tale caso riveste importanza ai fini della migliore
applicazione dell’algoritmo.
Studio Asintotico: è lo studio della funzione di complessità al
crescere della dimensione N del problema. Tale studio fornisce
indicazioni utili ai fini del raggruppamento degli algoritmi
suddividendoli in base a ordini o classi di funzioni di
complessità (si noti che può capitare anche che per piccole
dimensioni del problema l’algoritmo abbia un comportamento anomalo
rispetto alle grandi dimensioni).
Nello studio asintotico interessa in sostanza sapere se esiste
una funzione f(N) e 2 costanti intere positive N0 e c tali che per
NN0 si abbia C(N)c*f(N), se f(N) esiste allora si dice che C(N)
cresce come o è proporzionale o dello stesso ordine di f(N) - in
termini grafici questo significa che da N0 in poi C(N) è al di
sotto di o delimitata da c*f(N) - ciò che si indica con la
cosiddetta notazione O-grande (big-o notation): C(N)=O(f(N)).
In tal modo si possono definire scale o ordini di complessità e
confrontare classi di algoritmi in base alle relative funzioni di
complessità (vedi slide FLM41).
Complessità Asintotiche (esempi)
C(N) = O(1)
Costante (caso migliore)
C(N) = O(LogbN)
Logaritmica (caso buono)
C(N) = O(Nk)
Polinomiale (k>1)
(Lineare per K=1, Sottolineare per k<1)
C(N) = O(aN)
prof. Felice Zampini
Esponenziale (a>1; caso peggiore).
Fondamenti Logici e Metodologici
31/34
Complessità degli Algoritmi
Per quanto visto, la complessità C(A) di un algoritmo A è una
funzione (valutabile nei 4 casi considerati) dei seguenti elementi
rilevanti dell’algoritmo:
 Dimensione N del problema;
 Tipi di operazioni da fare per eseguire A;
 Numero di operazioni eseguite da A.
Due algoritmi A e B si dicono confrontabili se:
 Risolvono la stessa classe di problemi;
 Operano sullo stesso insieme di dati di dimensione N;
 C(A) e C(B) sono funzioni degli stessi parametri rilevanti.
Se A e B sono confrontabili allora si dice che A è migliore di
B se per ogni valore dei parametri rilevanti risulta C(A)<C(B), in
altri termini, indicate con O(f(N)) e O(g(N) le funzioni di
complessità di A e B allora A è migliore di B se per ogni valore
dei parametri rilevanti si ha f(N)<g(N).
Valori di Taglio
Il confronto tra algoritmi tramite le relative funzioni di
complessità potrebbe dar luogo a situazioni in cui risulti A
migliore di B solo limitatamente a certi intervalli di N, in tal
caso è importante determinare tali intervalli.
Dati 2 algoritmi confrontabili A e B si dice Valore di Taglio
tra A e B di un parametro rilevante p quel valore t tale che t è
il massimo dei valori di p percui si ha C(B)<C(A).
Se per ogni pt risulta C(B)<C(A) allora per tali valori B è
migliore di A mentre per tutti i valori p>t risulta A migliore di
B.
In modo analogo, le considerazioni appena svolte si possono
applicare
ai
programmi,
introducendo
delle
costanti
di
proporzionalità nelle funzioni di complessità allo scopo di
rappresentare, come già osservato, gli effetti di complessità
dovuti al contesto: se C(A)=a*f(N) e C(B)=b*g(N) e f(N)<g(N) si
dice valore di taglio quel valore Nt tale che per ogni NNt si ha
b*g(N)a*f(N).
La slide FLM41 illustra quanto detto.
prof. Felice Zampini
Fondamenti Logici e Metodologici
32/34
Computabilità
L’analisi della complessità asintotica consente di dedurre una
serie di considerazioni che esulano dagli scopi di questa
trattazione introduttiva.
In particolare, con riferimento alla slide FLM41 ed a quanto
detto, giova comunque fare qualche osservazione.
Nella classe degli algoritmi (o dei programmi) computabili
quelli con complessità esponenziale rappresentano casi critici,
infatti i tempi di esecuzione di tali algoritmi diventano enormi
anche per piccoli valori del parametro N e sono praticamente
indipendenti dalla velocità dell’elaboratore utilizzato (anche se
ipoteticamente supposto velocissimo).
Tali algoritmi sono da ritenersi pertanto non effettivamente
computabili, cioè rappresentano problemi intrattabili (almeno al
livello delle attuali conoscenze).
Di norma, si considerano come algoritmi effettivamente
computabili quelli di complessità al più polinomiale, inoltre, se
la complessità può essere espressa da un polinomio, si ha che il
suo ordine è rappresentato dal grado del polinomio.
prof. Felice Zampini
Fondamenti Logici e Metodologici
33/34
CICLO DI VITA DEL SOFTWARE
Per Ciclo di Vita del Software s’intende una scomposizione del
processo di produzione del software basata in genere su una
sequenza ordinata di fasi temporali ben definite e controllabili.
Si hanno vari modelli di cicli di vita del software, differenti
a seconda del livello di dettaglio e di specializzazione; visto il
carattere (necessariamente) introduttivo di questo paragrafo,
saranno quì fornite solo delle schematizzazioni orientative di
carattere generale.
La slide FLM42 illustra un MODELLO A CASCATA (Waterfall Model) del
ciclo di vita del software, fondamentalmente caratterizzato dalla
proprietà che ogni fase è dotata di un’interfaccia verso la
successiva e di un processo di verifica e controllo.
La slide FLM43 illustra un
diversificazione e delucidazione.
modello
analogo
con
qualche
Oltre a quanto già visto fino a questo punto, in particolare
nel paragrafo Complessità, giova almeno elencare talune altre
questioni che intervengono nell’ambito del ciclo di vita del
software (questioni concernenti l’INGEGNERIA DEL SOFTWARE).
MISURA
DELLE PRESTAZIONI DEI CALCOLATORI:
 IER – INSTRUCTION EXECUTION RATE (MIPS)
 ETR – EXTERNAL THROUGHPUT RATE (N.
TASK/TEMPO)
 ITR – INTERNAL THROUGHPUT RATE (N.
TASK/TEMPO
-
DI
CPU
ATTIVA)
 RESPONSE TIME (SEC)
 BENCHMARK (SEC)
TECNICHE
PER LA PREVENZIONE DEGLI ERRORI:
 INSPECTION
 WALKTHROUGH
Approfondimenti
lezioni.
prof. Felice Zampini
saranno
svolti
nel
Fondamenti Logici e Metodologici
seguito
e
durante
le
34/34
Scarica