Algoritmo = Dati e Azioni Dati: Numeri (naturali, interi, reali, …) Caratteri alfanumerici (a, b, c, …) Dati logici (vero, falso) Vettori di elementi, matrici, … ([1,2,3], [[1,1],[1,2],…]) Azioni o istruzioni: Istruzioni di ingresso/uscita (es. leggi, visualizza,…) Istruzioni aritmetico-logiche (es. c = a * b) Istruzioni di controllo (es. se … allora, ripeti…) Sistema numerico binario Il sistema numerico binario è un sistema numerico posizionale in base 2, cioè che utilizza 2 simboli, tipicamente 0 e 1, invece dei 10 del sistema numerico decimale tradizionale. Di conseguenza, la cifra in posizione N (da destra) si considera moltiplicata per 2N (anziché per 10N come avverrebbe nella numerazione decimale). Ecco una tabella che confronta le rappresentazioni binarie, esadecimali e decimali di alcuni numeri: binario esadecimale decimale 0000 = 0 = 0 0001 = 1 = 1 0010 = 2 = 2 0011 = 3 = 3 0100 = 4 = 4 0101 = 5 = 5 0110 = 6 = 6 0111 = 7 = 7 1000 = 8 = 8 1001 = 9 = 9 1010 = A = 10 1011 = B = 11 1100 = C = 12 1101 = D = 13 1110 = E = 14 1111 = F = 15 È usato in informatica per la rappresentazione interna dei numeri, grazie alla semplicità di realizzare fisicamente un elemento con due stati anziché un numero superiore, ma anche per la corrispondenza con i valori logici vero e falso. Rappresentazioni di numeri binari I numeri binari, in campo informatico, non sono utilizzati esclusivamente per memorizzare numeri interi positivi ma, mediante alcune convenzioni, è possibile scrivere numeri binari con segno e parte decimale senza introdurre nuovi caratteri (come la virgola e il segno meno, non memorizzabili su di un bit). Rappresentazione in modulo e segno Questo è il modo più semplice per rappresentare e distinguere numeri positivi e negativi: al numero binario vero e proprio viene anteposto un bit che, per convenzione, assume il valore 0 se il numero è positivo ed assume il valore 1 se il numero è negativo. Il grande difetto di questa rappresentazione è quello di avere due modi per scrivere il numero 0: 00000000 e 10000000 significano infatti +0 e -0. Rappresentazione in complemento a 2 Questo metodo di rappresentazione ha notevoli vantaggi, soprattutto per effettuare somme e differenze: in pratica ai numeri viene anteposto un bit di valore zero; se poi il numero è negativo è necessario convertirlo in complemento a 2: per farlo è sufficiente leggere il numero da destra verso sinistra e invertire tutte le cifre a partire dal primo bit pari a 1 (escluso). Per fare un esempio: − 1210 = − 011002 = 10100CA2 Come è possibile notare seguendo questo metodo il primo bit diventa automaticamente il bit del segno (come per il metodo precedente). Viene però risolto il problema dell'ambiguità dello 0 (in complemento a 2 00000 e 10000 hanno significati diversi) e vengono enormemente facilitate le operazioni di somma e differenza, che si riducono alla sola operazione di somma: per spiegare meglio basta fare un esempio: 510 − 1010 = 510 + ( − 10)10 = 01012 − 10102 = 00101CA2 + 10110CA2 = 11011CA2 = − 001012 = − 510 Rappresentazione a virgola fissa Dato che in un bit non è rappresentabile la virgola il metodo più semplice per rappresentare numeri frazionari è quello di scegliere arbitrariamente la posizione della virgola (ad es. se si sceglie di usare 4 bit per la parte intera e 4 per la parte frazionaria: 101001012 significa 1010,01012). Rappresentazione in virgola mobile Esistono innumerevoli modi per rappresentare numeri in virgola mobile ma il sistema più utilizzato è lo standard IEEE P754; questo metodo comporta l'utilizzo della notazione scientifica, in cui ogni numero è identificato dal segno, da una mantissa (1,xxxxx) e dall'esponente (nyyyyy). La procedura standard per la conversione da numero decimale a numero binario P754 è la seguente: 1. Prima di tutto il numero, in valore assoluto, va convertito in binario. 2. Il numero va poi diviso (o moltiplicato) per 2 fino a ottenere una forma del tipo 1,xxxxxx. 3. Di questo numero viene eliminato l'1 iniziale (per risparmiare memoria) 4. Il numero di volte per cui il numero è stato diviso (o moltiplicato) per 2 rappresenta l'esponente: questo valore (decimale) va espresso in eccesso 127, ovvero è necessario sommare 127 e convertire il numero risultante in binario. Nel caso di rappresentazione a precisione doppia (v. definizione seguente) il valore dell'esponente viene espresso in eccesso 1023. A questo punto abbiamo raccolto tutti i dati necessari per memorizzare il numero: in base al numero di bit che abbiamo a disposizione possiamo utilizzare tre formati: il formato a precisione singola (32 bit), il formato a precisione doppia (64 bit) e il formato a precisione quadrupla (128 bit). 1. Nel primo caso possiamo scrivere il valore utilizzando 1 bit per il segno, 8 bit per l'esponente e 23 bit per la mantissa. 2. Nel secondo caso servirà 1 bit per il segno, 11 bit per l'esponente e 52 per la mantissa. 3. Nel terzo caso servirà 1 bit per il segno, 15 bit per l'esponente e 112 per la mantissa. Per esempio, convertiamo il valore − 14,312510 in binario P754 single: 1. Convertiamo prima di tutto il numero: 1410 = 11102 per la parte intera e 0,312510 = 0,01012. Quindi il numero definitivo è 1110,01012 (segno escluso). 2. Dividiamo poi il numero per 2 per ottenere la seguente notazione: 1110,01012 = 1,11001012 * 23 3. La mantissa diventa, quindi: 1100101. 4. Per esprimere l'esponente in eccesso 127, infine: 127 + 3 = 13010 = 100000102 Il numero, alla fine, sarà espresso nel formato: 1 10000010 11001010000000000000000 Sistema numerico esadecimale Il sistema numerico esadecimale (spesso abbreviato come esa o hex) è un sistema numerico posizionale in base 16, cioè che utilizza 16 simboli invece dei 10 del sistema numerico decimale tradizionale. Per l'esadecimale si usano in genere simboli da 0 a 9 e poi le lettere da A a F, per un totale di 16 simboli. Il sistema esadecimale è molto usato in informatica, per la sua relazione diretta tra una cifra esadecimale e quattro cifre binarie. È spesso usato come intermediario, oppure come sistema numerico a sé stante. Per esempio, è possibile esprimere un byte con esattamente due cifre esadecimali (invece che con 3 decimali). Ci sono numerosi modi per denotare un numero come esadecimale, usati in differenti linguaggi di programmazione: Il C e i linguaggi con una sintassi simile (come il Java) usano il prefisso '0x', per esempio "0x5A3". Lo zero iniziale è presente perché i numeri devono iniziare con un carattere numerico, e la 'x' significa esadecimale (in caso di assenza della 'x', il numero è inteso come ottale. Il Pascal e alcuni Assembly indicano l'esadecimale con il suffisso 'h' (se il numero inizia con una lettera, si usa anche il prefisso '0'), per esempio "0A3Ch", "5A3h". Un metodo per convertire un numero esadecimale in decimale è quello di moltiplicare le sue cifre per le potenze della base 16. quindi (Si ricorda che 160 = 1) Allora L'operazione inversa - da decimale ad esadecimale - si realizza con una serie di divisioni successive. Conversione dal sistema esadecimale al sistema binario e viceversa La ragione per cui si adopera in informatica il sistema esadecimale è che può essere considerato come una scrittura più compatta del sistema binario. La conversione dalla base 16 alla base 2 e viceversa può essere svolta per sostituzione di gruppi di cifre invece che con algoritmi di divisione. Ad esempio, si consideri il seguente numero in base 16: A16BC916. Per convertilo in base 2, è sufficiente prelevare ciascuna cifra esadecimale e sostituirla con il suo equivalente nel sistema binario. Seguendo questa procedura, si perviene al seguente risultato: A16BC916 = A 1 6 B C 916 = 1010 0001 0110 1011 1100 10012 = 1010000101101011110010012 Per ottenere la conversione opposta, invece, bisogna procedere nella maniera inversa: si suddivide il numero binario in gruppi di 4 cifre a partire da destra (se l'ultimo gruppo contiene meno di 4 cifre, vanno anteposti tanti zeri quanti servono per completarlo) e si sostituisce ogni gruppo con il suo equivalente esadecimale. Supponiamo ad esempio di convertire in base 16 il numero in base 2: 1001011111110010112. Effettuando le operazioni descritte in precedenza si ha: 1001011111110010112 = 0010 0101 1111 1100 10112 = 2 5 F C B16 = 25FCB16 Rappresentazione dei caratteri: codice ASCII ASCII è l'acronimo di American Standard Code for Information Interchange (ovvero Codice Standard Americano per lo Scambio di Informazioni), è un sistema di codifica dei caratteri a 7 bit comunemente utilizzato nei calcolatori, proposto dall'ingegnere dell'IBM Bob Bemer nel 1961, e successivamente accettato come standard dall'ISO. Per non confonderlo con le estensioni a 8 bit proposte successivamente, questo codice viene talvolta riferito come US-ASCII. Alla specifica iniziale basata su codici di 7 bit fecero seguito negli anni molte proposte di estensione ad 8 bit, con lo scopo di raddoppiare il numero di caratteri rappresentabili. Nei PC IBM si fa per l'appunto uso di una di queste estensioni, ormai standard di fatto, chiamata extended ASCII o high ASCII. In questo ASCII esteso, i caratteri aggiunti sono vocali accentate, simboli semigrafici e altri simboli di uso meno comune. ISO 8859 In seguito al proliferare di codifiche proprietarie, l'ISO rilasciò uno standard denominato ISO 8859 contenente un'estensione a 8 bit del set ASCII. Il più importante fu l'ISO 8859-1, detto anche Latin1, contenente i caratteri per i linguaggi dell'Europa Occidentale. Furono standardizzate codifiche per gli altri linguaggi: ISO 8859-2 per i linguaggi dell'Europa Orientale, ISO 8859-5 per i caratteri cirillici e molti altri. Una particolarità dell'ISO 8859 rispetto agli altri caratteri estesi è che i caratteri dal 128 al 159, i cui 7 bit più bassi corrispondono ai caratteri di controllo ASCII, non sono usati per non creare problemi di compatibilità. Microsoft successivamente creò la code page 1252, un set compatibile con l'ISO 8859-1 che riempie anche questi 32 caratteri, che divenne lo standard per le versioni europee di Windows. UNICODE Una nuova codifica chiamata Unicode fu sviluppata nel 1991 per poter codificare più caratteri in modo standard e permettere di utilizzare più set di caratteri estesi (es. greco e cirillico) in un unico documento; questo set di caratteri è oggi largamente diffuso. Inizialmente prevedeva 65.536 caratteri ed è stato in seguito esteso a 1.114.112 e finora ne sono stati assegnati circa 101.000. I primi 256 caratteri ricalcano esattamente quelli dell'ISO 8859-1. La maggior parte dei codici sono usati per codificare lingue come il cinese, il giapponese ed il coreano, ma vi sono anche caratteri appartenenti a lingue più esotiche come il klingon. Algebra di Boole I fondamenti dell’algebra Booleana sono stati delineati dal matematico inglese George Boole in un lavoro pubblicato nel 1847 riguardante l’analisi della logica e in particolare l’algebra della logica. Questa algebra include una serie di operazioni che si effettuano su delle variabili, dette appunto variabili booleane, che permettono di codificare le informazioni su due soli livelli. Nell'algebra di Boole essendo, a differenza di quella tradizionale, un'algebra binaria, le variabili possono assumere soltanto due stati: 0/1; v/f ( vero, falso); l/h (low, high); t/f (true, false); on/off; (acceso/spento) Ad esempio la variabile logica x può avere valore vero o valore falso. La variabile logica oggi_piove ha associato un valore che indica appunto se oggi piove oppure no, quindi può essere vera oppure no. Le Funzioni logiche o booleane sono funzioni che associano ad una sequenza di variabili booleane un valore booleano, ad esempio: F(x,y,z) La funzione F associa in base ai tre valori logici assunti dalle variabili logiche x,y,z un valore logico vero o falso. Si può osservare che si hanno solo 8 possibilità per i valori assunti dalle tre variabili: 1. x falso, y falso, z falso 2. x falso, y falso, z vero 3. x falso, y vero, z falso 4. x falso, y vero, z vero 5. x vero, y falso, z falso 6. x vero, y falso, z vero 7. x vero, y vero, z falso 8. x vero, y vero, z vero Per ognuna di queste otto possibilità la funzione F assume valore vero oppure falso. Un modo semplice per rappresentare graficamente questa associazione usa una tabella detta tabella di verità: x F F F F V V V V y F F V V F F V V z F V F V F V F V F(x,y,z) V F F V V F F V L’algebra di Boole introduce tre operatori di base AND, OR e NOT tramite i quali può essere espressa qualsiasi funzione logica. Notazione: prodotto logico somma logica negazione vero falso a AND b a OR b NOT a true false a∧b a∨b ¬a T ⊥ a⋅b a+b a 1 0 Le precedenti sono tre notazioni diverse per esprimere i tre operatori logici, la prima è una notazione “linguistica” ed è usata in molti linguaggi di programmazione, la seconda è la notazione matematica, la terza è la notazione aritmetica che enfatizza la similarità tra l’algebra booleana e l’algebra dei numeri. Nella logica le variabili logiche sono chiamate anche proposizioni semplici. Mentre le espressioni booleane che contengono operatori AND, OR e NOT sono chiamate anche proposizioni composte. Esempio di proposizione semplice o variabile logica: a Esempio di proposizione composta o espressione logica: a AND NOT b OR c L’esempio precedente è ambiguo perché potrebbe essere interpretato nei modi seguenti: ( a AND (NOT b)) OR c a AND ( (NOT b) OR c) a AND ( NOT ( b OR c)) Per risolvere l’ambiguità o si usano obbligatoriamente le parentesi oppure si assume un ordine di priorità degli operatori, quello usuale è NOT, AND, OR. Questo vuol dire che nel valutare una espressione prima si valutano i NOT poi gli AND e poi gli OR, questo corrisponde alla prima interpretazione riportata. Questo è anche l’ordine con cui si risolve comunemente l’ambiguità nelle espressioni algebriche numeriche con gli operatori -, ⋅ e + infatti l’espressione a ⋅ –b + c viene comunemente interpretata come ( a ⋅ ( - b ) ) + c. OPERATORI DI BASE: AND, OR, NOT A AND B è una funzione logica che è vera solo se entrambi gli operandi A e B sono veri. A B A AND B F F F V F F V F F V V V A OR B è una funzione logica che è vera solo se almeno uno dei due operandi A o B è vero. A B A OR B F F F V F V V F V V V V NOT A è una funzione logica che inverte il valore logico del suo operando. A NOT A V F F V Questi operatori possono essere combinati per scrivere delle espressioni logiche: A AND ( B OR ( NOT A ) ) ( NOT X ) OR X Nelle espressioni logiche si possono usare anche due costanti logiche true e false ad indicare il valore logico vero e il valore logico falso. A AND (B OR true) Esattamente come per gli operatori aritmetici +, -, *, / gli operatori logici hanno delle proprietà che permettono di manipolare le espressioni logiche lasciando invariato il valore logico della espressione. Proprietà: Simmetrica A AND B = B AND A A OR B = B OR A Associativa A AND ( B AND C ) = ( A AND B ) AND C A OR ( B OR C ) = ( A OR B ) OR C Elemento neutro A AND true = A A OR false = A Elemento inverso A AND NOT A = false A OR NOT A = true Distributiva A AND ( B OR C ) = ( A AND B ) OR ( A AND C ) A OR ( B AND C ) = ( A OR B ) AND ( A OR C ) Idempotenza A AND A = A A OR A = A Assorbimento A OR ( A AND B ) = A A AND ( A OR B ) = A A AND false = false A OR true = true De Morgan NOT ( A AND B ) = (NOT A) OR (NOT B) NOT ( A OR B ) = (NOT A) AND (NOT B) Doppia negazione NOT NOT A = A AB=BA A+B = B+A A(BC)=(AB)C A+(B+C)=(A+B)+C A1=A A+0=A AA=0 A+A=1 A(B+C)=AB+AC A + ( B C ) = (A + B) (A +C) AA=A A+A=A A + (A B) = A A (A + B) = A A0=0 A+1=1 AB=A+B A+B=AB A=A Sulla sinistra le proprietà sono espresse nella notazione “linguistica” mentre a destra le stesse proprietà sono espresse nella notazione aritmetica. Si noti proprio come molte proprietà siano comuni con l'algebra dei numeri. Queste proprietà permettono di semplificare una espressione logica, vediamo un esempio: NOT (A OR (B AND NOT A)) = NOT ( (A OR B) AND (A OR NOT A)) = NOT ( (A OR B) AND true ) = NOT ( A OR B ) = NOT A AND NOT B -- prop. distributiva -- elemento inverso OR -- elemento neutro AND -- De Morgan Data una espressione booleana si può trovare la tabella della verità che la rappresenta. Esempio: L’espressione (A AND (NOT B)) OR C è una funzione booleana di 3 variabili logiche quindi la tabella di verità è fatta nel seguente modo: A B C (A AND (NOT B) ) OR C F F F ? F F V ? F V F ? F V V ? V F F ? V F V ? V V F ? V V V ? Per determinare il valore dell’espressione si può determinare il valore delle sotto espressioni che compongono l’espressione iniziale, prima NOT B, poi A AND (NOT B) ed infine tutta l’espressione (A AND (NOT B)) OR C: A B C NOT B A AND (NOT B) (A AND (NOT B) ) OR C F F F V F F F V F F V V F V F F F F F V V F F V V F F V V V V F V V V V V V F F F F V V V F F V Si può fare anche il contrario, cioè data una tabella di verità si può determinare una espressione logica equivalente, vediamo come con un esempio: x y z F(x,y,z) F F F F F F V F F V F F F V V F V F F V V F V V V V F V V V V F Si considerano i valori di x,y e z per cui F(x,y,z) è vera, per ognuno si ottengono delle espressioni booleane: si mettono in AND le variabili che sono vere e le variabili negate che sono false. Quindi si mettono in OR tra loro le espressioni ottenute. Il primo valore vero di F si ha per x vero, y falso e z falso che genera la sotto espressione: x AND (NOT y) AND (NOT z) Questa espressione è vera solo per x falso, y vero e z falso. Il secondo valore vero di F si ha per x vero, y falso, z vero che genera la sotto espressione: x AND (NOT y) AND z Il terzo ed ultimo valore vero di F si ha per x vero, y vero, z falso che genera la sotto espressione: x AND y AND (NOT z) Componendo queste espressioni con l’operatore OR si ottiene l’espressione che rappresenta la funzione booleana: (x AND (NOT y) AND (NOT z)) OR (x AND (NOT y) AND z) OR (x AND y AND (NOT z)) Questo metodo di scrittura viene denominato forma canonica. Semplificazione tramite mappa di Karnaugh La mappa di Karnaugh è un metodo di rappresentazione esatta di sintesi di reti combinatorie a uno o più livelli. Una tale mappa costituisce una rappresentazione visiva di una funzione booleana in grado di mettere in evidenza le coppie di mintermini o di maxtermini a distanza di Hamming unitaria (ovvero di termini che differiscono per una sola variabile binaria). Siccome derivano da una meno intuitiva visione delle funzioni booleane in spazi {0,1}n con n numero delle variabili della funzione, le mappe di Karnaugh risultano applicabili efficacemente solo a funzioni con al più 5 - 6 variabili. Le mappe di Karnaugh permettono di costruire semplicemente la forma minima di una funzione come somma di prodotti logici (forma congiuntiva) o come prodotto di somme logiche (forma disgiuntiva) e quindi semplificazioni della funzione booleana spesso più immediate di quelle ottenibili con modifiche algebriche. Per vedere come funziona una mappa di Karnaugh sfruttiamo il precedente esercizio, in particolare la forma canonica della funzione ottenuta: (x AND (NOT y) AND (NOT z)) OR (x AND (NOT y) AND z) OR (x AND y AND (NOT z)) Quindi andiamo a costruire la mappa: xy 00 01 10 11 0 0 0 1 1 1 0 0 1 0 z Nella mappa sono stati riportati i valori di falsità e verità (nel formato numerico) evidenziando due coppie di mintermini, questo permette di riscrivere la funzione tralasciando quelle variabili che all’interno della coppia non hanno un valore costante: (x AND (NOT z)) OR (X AND (NOT y)) Andando poi a semplificare aritmeticamente la funzione trovata otteniamo quanto segue: x AND ((NOT z) OR (NOT y)) x AND (NOT (z AND y)) Reti logiche Le reti logiche sono strettamente legate all’algebra di boole, sono reti composte da tre tipi di elementi (AND, OR e NOT) collegati tra loro. Ogni elemento ha degli ingressi booleani (sulla sinistra) ed una uscita booleana (sulla destra) gli elementi hanno una rappresentazione grafica che è la seguente: Un uscita di un elemento può essere collegata ad un ingresso di un altro elemento per realizzare una rete logica. Una rete logica ha un insieme di segnali booleani di ingresso e un insieme di segnali booleani di uscita vediamo un esempio: Questa rete ha due ingressi X e Y ed una uscita F, a questa rete può essere associata un’espressione booleana che determina il valore di F in funzione di X e Y, in questo caso si ha: F = ( NOT (X AND Y) ) AND ( (NOT X) OR Y ) Data un’espressione booleana si può determinare una rete logica che la calcola. L’importanza delle reti logiche è dovuta al fatto che i componenti elementari AND, OR e NOT possono essere realizzati utilizzando componenti elettronici (transistor) dove il valore vero/falso è rappresentato da un valore di tensione alto o basso. Vediamo come è possibile realizzare la somma tra numeri binari utilizzando delle reti logiche. Osserviamo che la cifra 0 può essere rappresentata dal valore booleano falso e la cifra 1 dal valore vero in base a questo si può determinare una espressione booleana che determina la somma di due cifre binarie e del riporto dalla cifra precedente e un’altra espressione che determina il riporto per la cifra successiva, questo può essere rappresentato con la seguente tabella della verità: r x y S R 0 0 0 0 0 0 0 1 1 0 0 1 0 1 0 0 1 1 0 1 1 0 0 1 0 1 0 1 0 1 1 1 0 0 1 1 1 1 1 1 Dove x e y sono le cifre binarie da sommare ed r è il riporto dalla cifra precedente, inoltre S è la somma ed R è il riporto per la cifra successiva. Data questa tabella di verità si possono determinare due espressioni logiche che calcolano S e R conoscendo r, x e y. Date queste due espressioni si può costruire una rete logica che le calcola usando componenti logici elementari (AND, OR e NOT): Utilizzando una serie di questi componenti che calcolano la somma di un bit si può realizzare un sommatore che somma 4 bit. Siano x3 x2 x1 x0 le cifre binarie del primo addendo e y3 y2 y1 y0 le cifre binarie del secondo addendo allora si possono ottenere le cifre binarie della somma S3 S2 S1 S0 utilizzando quattro componenti SB e connettendo il riporto ottenuto per una cifra alla cifra successiva: I calcolatori elettronici sono realizzati utilizzando milioni di componenti elementari AND/OR/NOT.