1.03k likes | 1.13k Views
CAPITOLO 13. PROGETTO. PROGRAMMA PRINCIPALE -. Program …………………...….. end. uses xxxx, yyyy;. unit xxxx ………………... end. MODULO 1 -. …………………………………………. unit yyyy ………………... end. MODULO n -. DATA ABSTRACTION. Qualunque tipo di dati può essere descritto sulla base dei valori
E N D
PROGETTO PROGRAMMA PRINCIPALE - Program …………………...….. end. uses xxxx, yyyy; unit xxxx ………………... end. MODULO 1 - …………………………………………. unit yyyy ………………... end. MODULO n -
DATA ABSTRACTION Qualunque tipo di dati può essere descritto sulla base dei valori che esso può prendere e delle operazioni che ad esso si possono applicare. ESEMPIO TipoValoriOperazioni integer - maxint ÷ + maxint +, -, *, DIV real 10-38 ÷ 10+38 +, -, *, / boolean TRUE, FALSE AND, OR, NOT
Un abstract data type (ADT) e’ un Type definito in termini del nome logico che gli si attribuisce e delle operazioni che possono essere applicate ad esso. DATA ABSTRACTION Separazione del significato logico delle operazioni in un ADT dai dettagli implementativi.
X = 5 X = -5 X = 3/2 X = 2 X = -1 X - 5 = 0 Numeri Naturali {gli interi da 0 a infinito} X + 5 = 0 Numeri Interi {gli interi da - infinito a infinito} 2X - 3 = 0 Numeri Razionali {i numeri che si ottengono come rapporto di due interi} X2 - 2 = 0 Numeri Reali {i numeri decimali periodici e non periodici } X2 + 1 = 0 Numeri Complessi {i numeri definiti nello spazio a due dimensioni R,i }
Nel 1572 tale Raffaele Bombelli, colui che per primo introdusse le parentesi, propose di trattare la come una entità a parte e di applicare ad essa tutte le regole che valevano per i numeri normali. Cartesio chiamò i numeri che prevedevano la presenza della numeri “immaginari” mentre Gauss li chiamò “complessi”. Solo nel 1777 Eulero propose di sostituire con la lettera “i”. I numeri complessi sono usati in elettrotecnica, dinamica dei fluidi, aerodinamica etc. Notizie sui numeri complessi si trovano in IL TEOREMA DEL PAPPAGALLO di Denis Guedj, ed. Longanesi, pag.326 IL LINGUAGGIO DELLA MATEMATICA di Keith Devlin ed. Bollati Boringhieri, pag. 159
NUMERI COMPLESSI Un numero complesso in genere è scritto come a + bi dove a e b sono dei numeri reali e i, detta parte immaginaria, è tale che i2=-1
i 3 2 2+1i 1 0 r -3 -2 -1 1 2 3 -1 -2-2i -2 -3 Rappresentazione grafica dei numeri complessi
TEOREMA FONDAMENTALE DELL’ALGEBRA Gauss 1799 Qualsiasi equazione polinomiale I cui coefficienti siano numeri complessi ha soluzioni all’interno dei numeri complessi
Progettare una ADT per i numeri complessi significa realizzare un software che permetta di definire un TypeComplesso e che implementi tutta una serie di operazioni tipiche dei numeri complessi. Es. addizione, sottrazione, moltiplicazione, divisione, valore assoluto, …………………………….. Una ADT, una volta implementata viene memorizzata su un file e richiamata da un programma solo quando richiesta. Ognuno di questi file è definito come unit e come tale è riconosciuto dal programma principale quando viene richiamato.
UNIT (pag. 906 testo Meyers) E’ un insieme di costanti, tipi, dati, variabili funzioni e procedure che può essere memorizzato su un file e compilato separatamente dal programma principale che lo chiama. Nel Turbo Pascal per compilare una unit si deve scegliere sotto la voce COMPILE l’option DISK (per i programmi generali si usa invece MEMORY). Per richiamare una unit in un programma si usa la parola chiave uses nome_unit, ….;
UNIT interfaccia Contiene le dichiarazioni globali a tutta la unit e le definizioni di procedure e funzioni da esportare implementazione Contiene i corpi delle procedure e funzioni sopra dichiarate insieme alle dichiarazioni di costanti, tipo, variabili e procedure locali all’unità. unit xxxxxxxx; interface ………. implementation ……………… end.
ComplexNo XRe YIm NUMERI COMPLESSI X + Yi TYPE ComplexNo=RECORD XRe, YIm: real END;
UNITADTComplexNo; {documentazione} INTERFACE {sezione interfaccia} {definizioni dell’ADT} TYPE ComplexNo=RECORD XRe, YIm: real END; { le operazioni } PROCEDURE …………………….. FUNCTION …………………………. IMPLEMENTATION {sezione implementazioni} PROCEDURE …………………….. FUNCTION ………………………….
NUMERI COMPLESSI a + bi Le operazioni con i numeri complessi: Parte Reale: a Parte Immaginaria: b Modulo: Somma : (a + bi) + (c + di) = (a + c) + (b + d) i Sottrazione: (a + bi) - (c + di) = (a - c) + (b - d) i Moltiplicazione: (a + bi) * (c + di) = (ac - bd) +(ad + bc) i Divisione:
UNITADTComplexNo; {documentazione} INTERFACE {inizio della sezione INTERFACE} { definizioni dell’ADT } TYPE ComplexNo=RECORD Xre, Yim: real END; { le operazioni } PROCEDURE MakeComp(Xpart, Ypart:real; VAR Cnumber: ComplexNo); { costruisci il numero complesso } FUNCTION RealPart(Cnumber: ComplexNo):real; { identifica la parte reale del numero complesso } FUNCTION ImaginaryPart(Cnumber: ComplexNo):real; { identifica la parte immaginaria del numero complesso } FUNCTION Magnitude(Cnumber: ComplexNo):real; { identifica il modulo del numero complesso }
PROCEDURE AddComp(Term1, Term2:ComplexNo; VAR Sum: ComplexNo); { addiziona i numeri complessi Term1 e Term2 } PROCEDURE SubtrComp(Term1, Term2: ComplexNo; VAR Difference: ComplexNo); { sottrae i numeri complessi Term1 e Term2 } PROCEDURE MultComp(Factor1, Factor2: ComplexNo; VAR Product: ComplexNo); { moltiplica i numeri complessi Factor1 e Factor2 } PROCEDURE DivComp(Factor1, Factor2: ComplexNo; VAR Quotient: ComplexNo); { divide i numeri complessi Factor1 e Factor2 } { fine della sezione INTERFACE }
IMPLEMENTATION {inizio della sezione IMPLEMENTATION} PROCEDUREMakeComp(Xpart, Ypart:real; VAR Cnumber: ComplexNo); { costruisci il numero complesso } BEGIN Cnumber.Xre:=Xpart; Cnumber.Yim:=Ypart END; FUNCTIONRealPart(Cnumber: ComplexNo):real; { identifica la parte reale del numero complesso } BEGIN RealPart:= Cnumber.Xre END; FUNCTIONImaginaryPart(Cnumber: ComplexNo):real; { identifica la parte immaginaria del numero complesso } BEGIN ImaginaryPart:= Cnumber.Yim END;
FUNCTIONMagnitude(Cnumber: ComplexNo):real; { identifica il modulo del numero complesso } BEGIN Magnitude:= sqrt(sqr(Cnumber.Xre)+sqr(Cnumber.Yim)) END; PROCEDUREAddComp(Term1, Term2:ComplexNo; VAR Sum: ComplexNo); { addiziona i numeri complessi Term1 e Term2 (a + bi) + (c + di) = (a + c) + (b + d) i } BEGIN WITH Sum DO BEGIN Xre:=Term1.Xre+Term2.Xre; Yim:=Term1.Yim+Term2.Yim END END;
PROCEDURESubtrComp(Term1, Term2:ComplexNo; VAR Difference: ComplexNo); { addiziona i numeri complessi Term1 e Term2 (a + bi) - (c + di) = (a - c) + (b - d) i } BEGIN WITH Difference DO BEGIN Xre:=Term1.Xre - Term2.Xre; Yim:=Term1.Yim - Term2.Yim END; END;
PROCEDUREMultComp(Factor1, Factor2:ComplexNo; VAR Product: ComplexNo); { addiziona i numeri complessi Term1 e Term2 (a + bi) * (c + di) = (ac - bd) +(ad + bc) i } BEGIN WITH Product DO BEGIN Xre:=Factor1.Xre * Factor2.Xre - Factor1.Yim * Factor2.Yim; Yim:=Factor1.Xre * Factor2.Yim + Factor2.Xre * Factor1.Yim END END;
PROCEDUREDivComp(Factor1, Factor2:ComplexNo; VAR Quotient: ComplexNo); { addiziona i numeri complessi Term1 e Term2 } VAR Divisor: real;{divisore del quoziente} BEGIN Divisor:=sqr(Factor2.Xre) + sqr(Factor2.Yim); WITH Quotient DO BEGIN Xre:=(Factor1.Xre * Factor2.Xre + Factor1.Yim * Factor2.Yim)/Divisor; Yim:= (Factor1.Yim *Factor2.Xre - Factor1.Xre * Factor2.Yim)/Divisor END END;
ESEMPIO Risolvere l’equazione di primo grado AX+B=C con A, B, C numeri complessi. Supponiamo A 0. Soluzione: X=(C-B)/A Input: Introdurre i coefficienti nell’ordine: A, B, C Per ogni coefficiente introdurre prima la parte reale e poi la parte immaginaria. Ouput: Mostrare la soluzione X sotto forma di numero complesso
Equazione A A B B X X C C Mostra Istr. Leggi Calcola Mostra Ris. ADTComplexNo ADTComplexNo ADTComplexNo Pseudo codice Richiama la unit per i numeri complessi; Mostra le istruzioni per l’introduzione dei dati; Leggi i coefficienti; Calcola la soluzione; Mostra la soluzione.
PROGRAM Equazione(input,output); USES Compl; VAR A,B,C, {coefficienti} X: ComplexNo; {soluzione} PROCEDURE MostraIstruzioni; BEGIN writeln('L'' equazione e'' immaginata sotto la forma AX+B=C. ' ); writeln('I coefficienti A,B,C vanno introdotti come coppie di numeri:'); writeln('prima la parte reale e poi quella immaginaria') END;
PROCEDURE MC(Z:ComplexNo); {mostra il numero complesso Z} VAR Segno:STRING[3]; BEGIN Segno:=’ - '; IF ImaginaryPart(Z)<>0 THEN BEGIN IF ImaginaryPart(Z)>0 THEN Segno:=' + '; writeln(RealPart(Z):3:1,Segno,ImaginaryPart(Z):3:1,'i') END ELSE writeln(RealPart(Z):3:1) writeln END;
PROCEDURE LeggiCoefficienti(VAR A,B,C:ComplexNo); VAR ARe,BRe,CRe,AIm,BIm,CIm:real; BEGIN write('Coefficiente A= '); readln(ARe,AIm); write('Coefficiente B= '); readln(BRe,BIm); write('Coefficiente C= '); readln(CRe,CIm); MakeComp(ARe,AIm,A); MakeComp(BRe,BIm,B); MakeComp(CRe,CIm,C) END;
PROCEDURE Soluzione(A,B,C:ComplexNo; VAR X:ComplexNo); {documentazione} VAR CmenoB:ComplexNo; BEGIN SubtrComp(C,B,CmenoB); DivComp(CmenoB,A,X) END; PROCEDURE MostraRisultato(X:ComplexNo); BEGIN writeln('La radice dell''equazione assegnata e'': '); MC(X) END;
{ BODY } BEGIN MostraIstruzioni; LeggiCoefficienti(A,B,C); Soluzione(A,B,C,X); MostraRisultato(X) END.
OUTPUT L' equazione e' immaginata sotto la forma AX+B=C. I coefficienti A,B,C vanno introdotti come coppie di numeri: prima la parte reale e poi quella immaginaria Coefficiente A= 5 66 Coefficiente B= 77 55 Coefficiente C= 4 2 La radice dell'equazione assegnata e': -0.9 + 1.0i
c b g d a h f e ESERCIZIO 1-B Progettare e realizzare una Unit che permetta il calcolo delle aree e dei perimetri delle seguenti figure geometriche: Triangolo rettangolo – assegnata la base e l’altezza Rettangolo – assegnata la base e l’altezza Pentagono e esagono - assegnato il raggio e il lato Utilizzando la Unit di cui sopra trovare l’area dell’appartamento la cui planimetria è data in figura assegnando alle dimensioni a,b,c,d,e,f valori a piacere (da tastiera) e per ogni vano calcolare la superficie complessiva dei muri sapendo che l’altezza di ogni vano vale k.
REGOLE GENERALI PER LA PROGETTAZIONE DI UNIT ADT Completezza: non necessita di operazioni addizionali per essere usata Ogni operazione deve appartenere ad una delle seguenti categorie: Constructor - cambia o inizializza i valori di una variabile astratta Primitive constructor - assegna un valore ad una variabile astratta senza fare uso di altre variabili astratte dello stesso tipo. Ha una sola variabile di output e quelle di input servono per costruire l’output. Es. MakeComp(Xpart, Ypart:real; VAR Cnumber: ComplexNo); { costruisci il numero complesso } Ogni ADT richiede almeno un Primitive constructor così che l'può assegnare un valore iniziale alla variabile astratta.
Non-primitive constructor -. Ha almeno una variabile di input il cui tipo è uguale a quello dell’output. Es. AddComp(Term1, Term2:ComplexNo; VAR Sum: ComplexNo); { addiziona i numeri complessi Term1 e Term2 }
SELECTOR - fornisce informazioni su una variabile di input ADT ad un parametro di uscita. Spesso è una funzione (il parametro di uscita in tal caso è la funzione stessa). Primitive selector - ritorna il valore di uno dei componenti della variabile astratta. Es. RealPart(Cnumber: ComplexNo):real; { identifica la parte reale del numero complesso } Ogni unit necessita di un Primitive selector altrimenti il client non può mostrare i valori della variabile. Non-primitive selector - ritorna il valore che non è relativo ad uno dei componenti della variabile astratta ma ciò nonostante è utile al client. Es. Magnitude(Cnumber: ComplexNo):real; { identifica il modulo del numero complesso }
PREDICATE - è una funzione booleana che ritorna informazioni sul valore o lo stato di una variabile astratta.
Un ADT è completa se il client : • fa riferimento solo al type dell’ADT (es. ComplexNo) • non deve mai cambiare la logica delle operazioni della unit • non deve mai aver bisogno di altre operazioni • Ogni unit ADT deve avere : • un primitive constructor • i valori devono poter essere letti e scritti • tutte le operazioni prevedibili per il tipo di ADT
Head Head Tail LE CODE (QUEUE)
LE CODE (QUEUE) Le operazioni fondamentali che si fanno sulle code sono: riempimento e svuotamento. Questo implica che durante lo svolgimento del programma il numero di oggetti in coda può cambiare. Dynamic data type: il numero di componenti nel Data Type cambia nel corso del programma. Dobbiamo descrivere una queue in funzione della sua head (testa), della sua tail (coda), degli oggetti in coda e del loro numero in ogni istante della computazione.
OPERAZIONI SULLE CODE In una coda l’elemento inserito per primo viene anche estratto per primo (FIFO). In una coda occorrerà allora distinguere tra un inizio o TESTA della coda (punto di estrazione e/o cancellazione di un elemento) ed una fine o CODA della coda (punto di inserimento di un nuovo elemento). Aggiungere ed eliminare oggetti. Se Items[ ] è un array in cui si collocano gli oggetti. Head l’indice dell’array corrispondente alla Testa, Tail l’indice corrispondente alla coda e Item l’oggetto da aggiungere potremmo usare i seguenti algoritmi:
OPERAZIONI SULLE CODE AGGIUNGERE Tail Tail+1 Items[Tail] Item InUse InUse + 1 ELIMINARE Head Head+1 InUse InUse - 1 SOLUZIONE IMPROPONIBILE !!!!!!!!!!!! Ogni volta che esce un oggetto bisogna spostare in avanti di un posto tutti quelli in coda altrimenti lo spazio disponibile si esaurisce rapidamente pur essendoci posti vuoti.
Testa N°=6 Coda Testa Coda 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 N°=6 Coda Testa N°=7 1 2 3 4 5 6 7 8 9 Escono due oggetti e ne entrano due Escono due oggetti e ne entrano tre
Possiamo descrivere una queue in funzione della sua head (testa), della sua tail (coda), degli oggetti in coda e del loro numero in ogni istante della computazione utilizzando l’espressione Tail:=Tail MOD MaxQueue + 1 Head:=Head MOD MaxQueue + 1 è infatti facile mostrare che con queste espressioni Tail e Head assumeranno giusto i valori indicati nella tabella precedente nel caso dell’esempio mostrato.
LE CODE (QUEUE) Le queue si riempiono aggiungendo oggetti in coda e si svuotano a partire dalla testa. Supponiamo di voler gestire con un meccanismo a coda 100 oggetti di tipo stringa.
QueueType Head Tail InUse Items UNITCode; {documentazione} INTERFACE {sezione interfaccia} {definizioni dell’ADT} CONST MaxQueue=100; NullItem=‘’; TYPE ItemType=STRING[20] massima lunghezza delle stringhe QueueType=RECORD Head, primo oggetto nella coda Tail : 1..MaxQueue; ultimo oggetto nella coda InUse :0..MaxQueue; numero di oggetti in coda Items: ARRAY[1..MaxQueue] OF ItemType contiene gli oggetti in coda END;
{ le operazioni } PROCEDURE MakeQueue(VAR Queue:QueueType); { inizializza la coda vuota } PROCEDURE AddQueue(Item:ItemType; VAR Queue:QueueType); { se la coda non è piena aggiungi oggetti altrimenti segnala errore } PROCEDURE DeleteQueue(VAR Queue:QueueType); {se la coda non è vuota elimina il primo oggetto altrimenti segnala errore} PROCEDURE FirstOnQueue(VAR Queue:QueueType; VAR Item:ItemType); {assegna a Item il valore del primo oggetto in coda, in mancanza assegna valore nullo}
FUNCTION QCount(VAR Queue:QueueType; ):integer; { identifica quanti oggetti sono in coda } FUNCTION QEmpty(VAR Queue:QueueType; ):boolean; { vera se non ci sono oggetti in coda } FUNCTION QFull(VAR Queue:QueueType; ):boolean; { vera se la coda è piena } { fine della sezione INTERFACE }
IMPLEMENTATION {inizio della sezione IMPLEMENTATION} QueueType Head Tail InUse Items PROCEDURE MakeQueue(VAR Queue:QueueType); { inizializza la coda vuota } BEGIN WITH Queue DO BEGIN Head:=1; Tail:=MaxQueue; InUse:=0 END END;
QueueType Head Tail InUse Items PROCEDURE AddQueue(Item:ItemType; VAR Queue:QueueType); { se la coda non è piena aggiungi oggetti altrimenti segnala errore } BEGIN WITHQueueDO IFInUse<>MaxQueueTHEN BEGIN Tail:=Tail MOD MaxQueue+1 Items[Tail]:=Item; InUse:=InUse+1 END ELSE writeln(‘Errore: la coda è piena’) END;
QueueType Head Tail InUse Items PROCEDURE DeleteQueue(VAR Queue:QueueType); {se la coda non è vuota elimina il primo oggetto altrimenti segnala errore} BEGIN WITHQueueDO IFInUse<>0THEN BEGIN Head:=Head MOD MaxQueue+1 InUse:=InUse-1 END ELSE writeln(‘Errore: la coda è vuota) END;