Ing. Elena Nardini – Università di Bologna – A.A. 2006/2007
Fondamenti di Informatica T2
Modulo 2
Università degli Studi di Bologna
Facoltà di Ingegneria
Corso di Laurea in Ingegneria Informatica
Anno accademico 2008/2009
2
Agenda
1. Creazione e test di un componente Frazione
2. Calcolo del codice fiscale
2
Ing. Elena Nardini – Università di Bologna – A.A. 2006/2007
Componente Frazione (1/2)
Realizzare un componente Frazione come tipo di dato astratto (ADT) progettato come tipo “valore” (una volta “nata” il suo valore è costante)
• dotato di una opportuna interfaccia che consenta di:
– Interfaccia di base
• Costruire una nuova frazione partendo da numeratore e denominatore
• Ottenere numeratore e denominatore della frazione
• Stabilire se la frazione è uguale ad una data
• Ottenere una rappresentazione stringa della frazione
• Ottenere una nuova frazione che rappresenti lo stesso valore in forma ridotta ai minimi termini
3
44
Componente Frazione (2/2)
– Interfaccia estesa
• Somma la frazione con un’altra e restituisce una nuova frazione che rappresenta il risultato
• Moltiplicare la frazione con un’altra e restituisce una nuova frazione che rappresenta il risultato
• Somma di un insieme di frazioni e restituisce una nuova frazione che rappresenta il risultato
• Moltiplicazione di un insieme di frazioni e restituisce una nuovafrazione che rappresenta il risultato
• …e di cui sia opportunamente verificato il funzionamento (il testing non è mai opzionale!!!)
– Verificare il corretto funzionamento di ogni singolo aspetto del componente.
Ing. Elena Nardini – Università di Bologna – A.A. 2006/2007
55
Premessa (1/2)
• Due generiche frazioni n / m e p / q sono equivalenti se vale la seguente uguaglianza: n * q = m * p.
ESEMPIO: 1/2 è equivalente a 3/6 e a 9/18
• È possibile determinare la forma minima equivalente di una frazione data; cioè è possibile trasformare una frazione in un’altra equivalente ed irriducibile. La riduzione ai minimi termini di una frazione si effettua dividendo il numeratore e il denominatore per il loro massimo comun divisore (M.C.D.)
ESEMPIO: il M.C.D del numeratore e denominatore della frazione 14/8 è 2 la frazione ridotta ai minimi termini è
7/4
66
Premessa (2/2)
• Il M.C.D. di due numeri è il più grande numero positivo intero che li divide senza resto
• È possibile calcolare in modo efficiente il M.C.D. di due numeri utilizzando l’algoritmo di Euclide
• L’algoritmo funziona nel seguente modo:
1. Supponiamo che a e b siano i valori di cui calcolare il M.C.D.
2. Se il resto della divisione fra a e b è uguale a zero, b rappresenta il M.C.D. fra a e b
3. Se invece il resto è diverso da 0, si pone a = b e b = resto e si riparte dal punto 2
IMPORTANTE: in Java, il resto della divisione fra due numeri a e b si calcola attraverso l’operatore % resto = a%b
Ing. Elena Nardini – Università di Bologna – A.A. 2006/2007
77
Realizzazione del componente
• ADT si possono avere tante entità dello stesso tipo quante ne servono
• In C occorre definire una struct, un po’ di funzioni e occorre gestire l’ allocazione esplicita della memoria
tramite malloc/free (funzioni di libreria) per creare
nuove entità.
• In Java occorre definire una classe, un po’ di metodi e
per creare nuove entità è sufficiente usare new (keyword
di linguaggio); una volta terminato di usare il componente (nessun riferimento punta più ad esso), il garbage collector si occuperà della deallocazione.
88
Realizzazione del componente• Stato del componente: è caratterizzato dai valori di
numeratore e denominatore– Interi
• Per costruire ci vuole un costruttore– Prende in ingresso sufficienti valori e li imposta nello stato
interno per far sì che, una volta costruita, la frazione sia in uno stato consistente almeno numeratore e denominatore altre situazioni?
• Se la frazione è negativa?– È negativo il numeratore o il denominatore?– E se sono negativi entrambi?– Comunque siano i parametri in ingresso al costruttore,
normalizziamo il tutto in modo che il segno sia conservato dal solo numeratore; il denominatore è sempre positivo.
Ing. Elena Nardini – Università di Bologna – A.A. 2006/2007
99
Realizzazione del componente
• Per costruire ci vuole un costruttore
– Prende in ingresso sufficienti parametri per far si che una volta costruita la frazione sia in uno stato consistente
almeno numeratore e denominatore
altre situazioni?
• Una volta che tali valori sono “dentro” l’entità, occorre poterli “vedere” da fuori– Due accessor pubblici (getX) che consentano di
ottenere numeratore e denominatore
1010
Realizzazione del componente
• Per cambiare numeratore e denominatore…
– GIAMMAI, sarebbe un suicidio informatico!
– Sarebbe come dire che il numero 3 vale cinque e non più tre…
– Piuttosto si può fare in modo che un riferimento ad una frazione punti non più alla frazione che vale 1/3 ma ad un’altra che vale 1/5…
– Poi, come si può avere la certezza che la frazione non sia condivisa? Sarebbe un dramma…
Ing. Elena Nardini – Università di Bologna – A.A. 2006/2007
1111
Realizzazione del componente• Rappresentazione in stringa (metodo toString)
– Un metodo che non ha in ingresso alcun parametro…– …poiché fornisce una rappresentazione dello stato interno dell’entità –
nel caso specifico il suo valore
• Test di uguaglianza/equivalenza (metodo equals)– Un metodo che prende in ingresso un’altra frazione ed indica se la
frazione presa in ingresso uguale a quella su cui è stato invocato il metodo
– In questo modo, il concetto di uguaglianza è definito dal programmatore
– Nel caso specifico “uguale” significa “equivalente” 3/12 equivale a ¼
• Riduzione ai minimi termini (metodo riduzioneMinimiTermini)– Restituisce una nuova frazione senza alterare quella su cui è stato
invocato il metodo…– Si tratta di valori costanti!
12
Test del componente
• Verificare il funzionamento di ogni parte
– Costruire la frazione
– Verificare che i metodi accessor restituiscano i valori attesi
– Verificare che il metodo toString restituisca la
rappresentazione attesa
– Verificare che il metodo riduzioneMinimiTermini
restituisca la frazione attesa
– Costruire altre frazioni e verificare che il metodo equals
si comporti nel modo atteso
12
Ing. Elena Nardini – Università di Bologna – A.A. 2006/2007
1313
Domanda
• La funzione relativa al calcolo dell’MCD è un metodo della classe Frazione?
• Si consideri che:– Il calcolo dell’MCD non serve solo per l’ADT Frazione
ma anche in altri contesti
– Il calcolo dell’MCD non ha necessità di uno stato
Il calcolo dell’MCD è un metodo statico e pubblico di una classe di “servizio” (MyMath)
1414
MyMathpublic final class MyMath
{
public static int mcd(int a, int b)
{
int resto;
if (b > a)
{
int tmp = a;
a = b;
b = tmp;
}
do
{
resto = a % b;
a = b;
b = resto;
}
while (resto != 0);
return a;
}
}
Ing. Elena Nardini – Università di Bologna – A.A. 2006/2007
1515
Frazione: stato e costruttori
public class Frazione
{
private int num, den;
public Frazione(int num, int den)
{
boolean negativo = num * den < 0;
this.num = negativo ? -Math.abs(num) : Math.abs(num);
this.den = Math.abs(den);
}
public Frazione(int num)
{
this(num, 1);
}
...
16
Frazione: accessors e minTerms
16
public int getNum()
{
return this.num;
}
public int getDen()
{
return den;
}
public Frazione minTerm()
{
int mcd = MyMath.mcd(Math.abs(getNum()), getDen());
int n = getNum() / mcd;
int d = getDen() / mcd;
return new Frazione(n, d);
}
…
Ing. Elena Nardini – Università di Bologna – A.A. 2006/2007
17
Frazione: equals e toString
17
public boolean equals(Frazione f)
{
return f.getNum() * getDen() == f.getDen() * getNum();
}
public String toString()
{
String frazione = "";
int num = getNum();
int den = getDen();
if (getDen() == 1)
frazione += num;
else
frazione += num + "/" + den;
return frazione;
}
}
1818
MyMainpublic class MyMain
{
public static void main(String[] args)
{
Frazione frazione1 = new Frazione(3, 12); // 3/12
System.out.println("Creata la frazione " + frazione1);
Frazione frazione2 = new Frazione(1, 4); // 1/4
System.out.println("Creata la frazione " + frazione2);
Frazione frazione3 = new Frazione(4, 1); // 4
System.out.println("Creata la frazione " + frazione3);
Frazione frazioneRidotta = frazione1.minTerm(); // 1/4
System.out.println("La frazione " + frazione1 + "
ridotta ai minimi termini diventa " + frazioneRidotta
+ "\n");
...
Ing. Elena Nardini – Università di Bologna – A.A. 2006/2007
1919
MyMainif (frazione1.equals(frazione2)) // true
System.out.println("Le frazioni " + frazione1 + " e " +
frazione2 + " sono equivalenti");
else
System.out.println("Le frazioni " + frazione1 + " e " +
frazione2 + " non sono equivalenti" + "\n");
if (frazione1.equals(frazione3)) // false
System.out.println("Le frazioni " + frazione1 + " e " +
frazione3 + " sono equivalenti");
else
System.out.println("Le frazioni " + frazione1 + " e " +
frazione3 + " non sono equivalenti" + "\n");
...
20
MyMain (valori negativi)
20
...
Frazione frazione4 = new Frazione(-1, 8); // -1/8
System.out.println("Creata la frazione " + frazione4);
Frazione frazione5 = new Frazione(2, -3); // -2/3
System.out.println("Creata la frazione " + frazione5);
Frazione frazione6 = new Frazione(-5, -7); // 5/7
System.out.println("Creata la frazione " +frazione6+"\n");
frazioneRidotta = frazione5.minTerm(); // -2/3
System.out.println("La frazione " + frazione5 + " ridotta
ai minimi termini diventa " +frazioneRidotta+ "\n");
}
}
Ing. Elena Nardini – Università di Bologna – A.A. 2006/2007
21
Estensione del componente
Estendere la classe Frazione con le seguenti
funzionalità:
• Somma di due frazioni
• Prodotto di due frazioni
• Somma di un insieme di frazioni
• Prodotto di un insieme di frazioni
21
22
Estensione del componente
• Come sono i metodi che realizzano le estensioni?
• Somma/Prodotto:– vengono invocati su una frazione– prendono in ingresso la frazione da sommare/moltiplicare– restituiscono una nuova frazione risultato dell’operazione
• Somma/Prodotto di un insieme di frazioni– Non ha senso, sebbene sia possibile, che possano essere
invocati su una frazione:• Quale di quelle dell’insieme?
– È sensato che siano metodi statici!• prendono in ingresso un array di frazioni• Restituiscono una nuova frazione risultato dell’operazione
22
Per realizzare entrambi i metodi si sfruttino i metodi somma e prodotto
Ing. Elena Nardini – Università di Bologna – A.A. 2006/2007
23
Codice: somma e prodotto
23
public class Frazione
{
private int num, den;
...
public Frazione sum(Frazione f)
{
int n = this.num * f.den + this.den * f.num;
int d = this.den * f.den;
return new Frazione(n, d);
}
public Frazione mul(Frazione f)
{
int n = this.num * f.num;
int d = this.den * f.den;
return new Frazione(n, d);
}
24
Codice: somma e prodotto su array di frazioni
24
public static Frazione sum(Frazione[] fs)
{
Frazione tmp = new Frazione(0, 1); // Elemento neutro
for (Frazione f : fs)
tmp = tmp.sum(f);
return tmp;
}
public static Frazione mul(Frazione[] fs)
{
Frazione tmp = new Frazione(1, 1); // Elemento neutro
for (Frazione f : fs)
tmp = tmp.mul(f);
return tmp;
}
}
Ing. Elena Nardini – Università di Bologna – A.A. 2006/2007
25
Trattamento degli errori• L’attuale “contratto di utilizzo” prevede che colui che crea la Frazione è
responsabile del risultato…
• Creare una frazione con zero al denominatore è possibile… ma prima o poi scoppia tutto
• Non è il massimo poiché il bug, in questo caso, è evidentemente a MONTE della costruzione mentre se ne subiscono le conseguenze a VALLE della stessa quando si usa la frazione
• Non avendo (ancora) un modo di interrompere brutalmente l’esecuzione e di notificare al chiamante il problema, quali soluzioni si possono trovare?– Ci vorrebbe qualcosa che verificasse i parametri PRIMA della costruzione– “Qualcosa” cosa?– Fatevi venire in mente “Qualcosa”…– …e anche come…
25
26
Calcolo del Codice Fiscale
• L’algoritmo è semplice
• Basta conoscere bene gli strumenti
• Oggi verrà progettata la soluzione
• In laboratorio la implementerete…
26
Ing. Elena Nardini – Università di Bologna – A.A. 2006/2007
27
Codice Fiscale: Regole
Riprendiamo le regole per il calcolo
• Cognome: le prime tre consonanti; se non bastano, le vocali; se non bastano ancora, una (o più) X– ROSSI RSS
– SUN SNU
– WU WUX
• Nome: la prima, la terza e la quarta consonante; se non ci sono quattro consonanti, si usano le prime tre; se non bastano, si usano le vocali; se non bastano ancora, una (o più) X– MARIO MRA
– GASTONE GTN27
28
Codice Fiscale: Regole
• Anno: le ultime due cifre
• Mese: A, B, C, D, E, H, L, M, P, R, S, T dove A è Gennaio, T è Dicembre
• Giorno:
– Uomini: il numero del giorno
– Donne: il numero del giorno aumentato di 40
01/02/1978 (maschio) 78B0125/12/1969 (femmina) 69T65
28
Ing. Elena Nardini – Università di Bologna – A.A. 2006/2007
29
Codice Fiscale: Regole• Comune di nascita: sigla che si trova su apposite tabelle:
– Bologna = A944– Reggio E. = H223– Alfonsine (RA) = A191– Jesi (AN) = E388– Ecc…
• Carattere di controllo: – Le cifre da 0 a 9 vengono sostituite dalle corrispondenti lettere da A
a J si ottiene un codice composto di sole lettere
– Alle lettere di posto pari viene assegnato un valore da 0 a 25, pari alla loro posizione nell’alfabeto (A = 0)
– Alle lettere di posto dispari viene assegnato un valore in base alla mappa:
B A K P L C Q D R E V O S F T
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14G U H M I N J W Z Y X15 16 17 18 19 20 21 22 23 24 25
– Si sommano tutti i valori di cui sopra e si prende il risultato modulo 26
29
30
Calcolo del Codice Fiscale: Progetto
• Per ognuna delle regole di cui sopra è bene predisporre un metodo diverso in modo da suddividere quindi semplificare il problema
• Tutti questi metodi faranno parte di una classe (è obbligatorio…)
• Per funzionare hanno bisogno di uno stato?– NO! SONO METODI STATICI!
• Un metodo “principale” avrà il compito di coordinare il lavoro di tutti gli altri e dovrà essere visibile dall’esterno (gli altri possono essere privati)– Façade
30
Ing. Elena Nardini – Università di Bologna – A.A. 2006/2007
31
Progetto: le mappe
• Nelle regole relative al mese e al carattere di controllo, viene utilizzata una mappa che consente di recuperare una lettera partendo da un numero
• Due possibilità:– Array: char[] mappa = new char[] {„B‟,„A‟,…};
– Stringa: String mappa = “BAK…”;
• In entrambi i casi la posizione di un carattere è il numero con cui si entra nella mappa– Array: char c = mappa[numero];
– Stringa: char c = mappa.charAt(numero);
• Perché è meglio la stringa dell’array?
31
32
Progetto: le mappe
• Una mappa “speciale” deve associare il nome del comune al relativo codice
– Metodo “più” stupido: creare una serie di if…else per il confronto della stringa in ingresso coi nomi dei comuni gestiti; quando si trova il match, output del codice relativo
– Metodo “meno” stupido: creare un array di oggetti che rappresentino delle coppie {Comune, Codice}…
32
Ing. Elena Nardini – Università di Bologna – A.A. 2006/2007
33
Progetto: vocali e consonantiCome riconoscere vocali e consonanti?
• Ipotesi: nome e cognome sono di sole lettere (no altri caratteri)
• Si può creare un “insieme” (nel senso dato precedentemente) che contenga le sole vocali (sono di meno!)…
• …e supporre che ciò che non è vocale non può che essere consonante…
• Ad esempio:– String VOCALI = "AEIOU“;
– char[] vocali = new char[]
{„A‟,‟E‟,‟I‟,‟O‟,‟U‟};
33
34
…omocodia?• Se c’è un problema di omocodia occorre applicare al
codice già creato la regola corrispondente sostituendo le cifre numeriche, a partire da destra, con le lettere della mappa che segue:0L 1M 2N 3P 4Q
5R 6S 7T 8U 9V
• Sostituire una cifra alla volta al bisogno…
• Un metodo statico pubblico che prende in ingresso un codice fiscale e ne produce un altro dopo aver sostituito UNA cifra.
34
Ing. Elena Nardini – Università di Bologna – A.A. 2006/2007
35
Interfaccia del componente
• Un metodo statico pubblico calcolaCodiceFiscale
– Input: cognome, nome, giorno mese e anno di nascita, comune di nascita, sesso
– Output: il codice fiscale
• Un metodo statico pubblico risolviOmocodia
– Input: un codice fiscale
– Output: un codice fiscale
35
36
Metodi privati• Metodi di utilità
– isConsonante: prende in ingresso un carattere e restituisce un booleano che indica se si tratta di una consonante
– Altro??
• Metodi di trasformazione– calcolaCognome: prende in ingresso il cognome e restituisce tre
lettere secondo la regola già espressa– calcolaNome: prende in ingresso il nome e restituisce tre lettere
secondo la regola già espressa– calcolaAnno: prende in ingresso l’anno e restituisce le ultime due
cifre– calcolaMese: prende in ingresso il mese e restituisce un carattere– calcolaGiornoSesso: prende in ingresso il giorno e il sesso e
restituisce due cifre– calcolaComune: prende in ingresso il comune e restituisce i
relativo codice– calcolaCarControllo: prende in ingresso TUTTO il codice
finora calcolato e restituisce il carattere di controllo corrispondente
36
Ing. Elena Nardini – Università di Bologna – A.A. 2006/2007
37
Altri metodi
• L’implementazione è: – una regola = un metodo
• Alcune regole sarebbe bene spezzarle in metodi diversi per fattorizzare e semplificare ulteriormente…
• Esempio:– metodo che si occupa di aggiungere vocali o X nella
codifica di nome/cognome (è uguale per entrambe le regole)
– …
37