ISTITUTO TECNICO E LICEO SCIENTIFICO TECNOLOGICO “ANGIOY” LA RAPPRESENTAZIONE DELLE INFORMAZIONI Prof. G. Ciaschetti DATI E INFORMAZIONI Sappiamo che il computer è una macchina stupida, capace di eseguire calcoli in modo velocissimo, ma non capace di pensare. Quando memorizziamo nel computer un qualsiasi dato, sia esso un numero, una parola, un‟immagine, un suono, non è possibile fare in modo che a questo dato il computer associ anche un significato: per fare questo, occorre un cervello pensante, come quello dell‟uomo, molto più intelligente di un computer. Facciamo qualche esempio: se diciamo che lo sconto su un paio di scarpe da tennis è del 20 per cento, sappiamo che il numero 20 rappresenta uno sconto, ma nel computer potrò inserire solo il numero 20, in quanto non esso non è capace di associare al numero il fatto che rappresenta uo sconto. Un altro esempio: se l‟età di una persona è 18 anni, il computer può memorizzare 18, ma non il fatto che questa sia un‟età. Funziona anche per le immagini, i suoni e i video: un‟immagine nel computer è solo un‟insieme di bit, messi in modo da dare un colore a ogni pixel dello schermo, ma il computer non sa assolutamente se l‟immagine che risulta riguarda una scena sportiva o una bella donna o qualsiasi altra cosa: l’uomo associa un significato ai dati, facendoli così diventare informazioni! Il computer, invece, sa trattare solo dati “grezzi” privi di significato, tutti rappresentati usando il linguaggio binario. Il linguaggio binario, come ogni linguaggio, è costruito su un alfabeto. L‟alfabeto binario, come è noto, è formato dai soli simboli 0 e 1 (a differenza dell‟alfabeto italiano che ha le 21 lettere A, B, …, Z o quello inglese che ha le 26 lettere A, B, …, Y, Z). Per costruire il linguaggio, a partire dall‟alfabeto, si usano parole. Mentre nei linguaggi naturali (quelli dell‟uomo, ad esempio, italiano, inglese, russo, ecc.) le parole possono avere dimensioni qualsiasi (pippo è una parola di 5 simboli, ciao di 4, ecc.), nel computer le parole hanno dimensione fissa, che dipende dal particolare computer. Solitamente, le parole possono essere di 1 byte, 2 byte, 4 byte oppure 8 byte. (un byte è una sequenza di 8 bit). Quindi, ad esempio, se un computer ha parole di 4 byte, esso userà sempre e solo parole formate con 32 simboli 0 o 1, cioè 32 bit. Quante parole è possibile formare con tutti i simboli di un alfabeto? Vale la seguente regola: con un alfabeto di n simboli, e parole formate da p simboli, si possono costruire np diverse parole. Esempio: se l’alfabeto è quello del sistema numerico decimale {0,1,…, 9} e abbiamo parole di 4 simboli, possiamo costruire tutte le 104 = 10000 parole 0000, 0001, 0002, 0003, …, 9999. Esempio: se l’alfabeto è quello binario {0,1} e abbiamo parole di 3 bit, possiamo costruire le 23 = 8 parole 000, 001, 010, 011, …, 111 (cioè tutti i numeri da 0 a 7). Esempio: se l’alfabeto è quello italiano {A,B,C,…,Z} e abbiamo parole di 2 lettere, possiamo costruire tutte le 212 = 441 parole AA, AB, AC, …,AZ, BA, BB, …, BZ, …, ZZ. Prima di iniziare la nostra trattazione su come sono rappresentati tutti i dati (e quindi le informazioni, per noi uomini) all‟interno del computer, un po‟ di definizioni: 1 byte = 8 bit 1 Kbyte (chilo) = 210 byte = 1024 byte 1 Mbyte (mega) = 210 Kbyte = 1024 Kbyte (= 220 byte) 1 Gbyte (giga) = 210 Mbyte = 1024 Mbyte (= 230 byte) 1 Tbyte (tera) = 210 Gbyte = 1024 Gbyte (= 240 byte) TIPI DI DATI Classificando i dati secondo il loro tipo, distinguiamo innanzitutto dati numerici e dati alfanumerici. I primi sono i numeri, così come li conosciamo dalla matematica, mentre gli altri comprendono le lettere e tutti i caratteri speciali (la virgola, il punto e virgola, le parentesi tonde, lo spazio bianco, ecc.). Tra i numeri, possiamo distinguere i numeri interi (che non hanno una parte decimale) e i numeri reali (che invece hanno una parte decimale). A loro volta, i numeri interi possono essere suddivisi in interi senza segno (solo interi positivi) e interi con segno (positivi e negativi). I numeri reali possono essere in singola o in doppia precisione, intendendo con precisione il grado di approssimazione che è possibile effettuare per i numeri irrazionali (che non possono essere memorizzati completamente in quanto hanno infinite cifre decimali). I dati alfanumerici possono essere singoli caratteri (come le lettera „A‟, „B‟, o i segni di punteggiatura, o le parentesi, o ogni altro simbolo che possiamo digitare sulla tastiera) o sequenze di caratteri dette stringhe (sono un po‟ come le nostre parole, ad esempio “pippo”, “ciao mondo”, ecc.). Impareremo, tra poco, come ognuno di questi tipi di dato è memorizzato nel computer, e quali sono i tipi predefiniti messi a disposizione dal linguaggio C, che sono riassunti nella seguente figura. RAPPRESENTAZIONE DEI NUMERI INTERI SENZA SEGNO Sono i numeri binari con cui abbiamo lavorato finora. Supponiamo di avere parole di 1 byte e consideriamo per il momento solo numeri interi positivi. I numeri che possiamo rappresentare con l‟alfabeto {0,1} su 8 bit sono tutti i numeri da 0 a 28-1 = 255. Se invece abbiamo parole di 2 byte, i numeri che possiamo rappresentare sono tutti quelli da 0 a 216-1 = 65535. In generale, con n bit si possono rappresentare tutti i numeri interi positivi da 0 a 2n -1. Linguaggio C: possono essere definiti i seguenti tipi di dato interi senza segno (positivi) Tipo di dato unsigned short int unsigned int unsigned long int numero di byte 2 byte 1 parola (2 o 4 byte, il numero dipende dal particolare computer) 4 byte Intervallo valori ammessi da 0 a 65535 da 0 a 4294967295 RAPPRESENTAZIONE DEI NUMERI INTERI CON SEGNO L‟insieme dei numeri interi comprende, oltre agli interi positivi, anche gli interi negativi. Come questi vengono rappresentati? Supponiamo sempre di avere parole di 2 byte. Dei 16 bit a disposizione, il primo bit a sinistra viene usato per il segno: 0 se il numero è positivo, 1 se il numero è negativo. In questo caso, per i numeri interi positivi rimangono 15 bit a disposizione, quindi, si ha la possibilità di rappresentare tutti i numeri da 0 a 32767. Se invece abbiamo parole di 1 byte, tolto un bit per il segno, restano 7 bit a disposizione con cui rappresentiamo tutti i numeri positivi da 0 a 27 – 1 = 127. In generale, se usiamo un bit per rappresentare il segno in un numero di n bit, ne restano a disposizione n-1 per il valore assoluto, e quindi potremo rappresentare i numeri positivi fino a 2n-1 -1. I numeri negativi, invece, sono rappresentati non in valore assoluto, ma in complemento a 2: il numero –N è rappresentato come il complemento a 2 del numero N. Ma cos‟è, esattamente, il complemento di un numero? data una base b, e un numero N in base b di n cifre, si definisce complemento di N il numero N(b) = bn - N Esempio: se b=10, e N = 982, risulta n = 3 e abbiamo 982(10) = 103 – 982 = 18 Esempio: se b=2, e N = 001, risulta n = 3 e abbiamo 001(2) = 23 – 1 = 111 Esempio: se b=10, e N = 24, risulta n = 2 e abbiamo 24(10) = 102 – 24 = 78 Dagli esempi, si può osservare che il complemento di un numero è quanto manca al numero per arrivare alla prossima potenza della base. Nel primo esempio, quanto manca a 982 per arrivare a 1000, nel secondo esempio quanto manca a 1 per arrivare a 8 in binario. Nel terzo esempio, quanto manca a 24 per arrivare a 100. Per trovare il complemento di un numero binario, anche detto complemento a 2, possiamo seguire una regola pratica molto semplice (di fatto, il computer fa così): si prende il numero in binario, si sostituisce ogni 0 con 1, e ogni 1 con 0, e poi si somma 1. Per far ciò, tuttavia, è necessario fissare il numero di bit della parola con cui sarà rappresentato il numero, altrimenti non funziona. Negli esempi che seguono, prendiamo parole di 1 byte, ma potrebbero tranquillamente essere di 2 byte, 4 byte o quanti vogliamo. Esempio: dato il numero 01010011 si scambiano le cifre si somma 1 complemento a 2 10101100 + 1= 10101101 Esempio: dato il numero 01011110 si scambiano le cifre si somma 1 complemento a 2 10100001 + 1= 10100010 Torniamo ai numeri negativi: abbiamo detto che sono rappresentati in complemento a 2. Ma come? Semplice, si scrive il numero come positivo, con tutti i bit a disposizione nella parola, e si fa il suo complemento applicando la regola appena vista. Supponendo ancora di avere parole di 1 byte, Esempio: rappresentazione di -5 rappresentiamo il 5 facciamo il suo complemento 00000101 11111011 Esempio: rappresentazione di -121 rappresentiamo il 121 facciamo il suo complemento 01111001 10000111 Possiamo verificare che il numero negativo così rappresentato è proprio l‟opposto del suo valore assoluto. Infatti, se fissiamo il numero di bit (ad esempio 8), e ignoriamo eventuali riporti su cifre eccedenti a sinistra, possiamo verificare quanto detto Esempio: 5 + (-5) = 0 rappresentazione di 5 rappresentazione di -5 somma 00000101 11111011 100000000 (sarebbe infatti 28 se potessimo prendere il nono bit) Facciamo anche un esempio supponendo di avere a disposizione parole di 2 byte. Esempio: rappresentazione di -65 rappresentiamo il 65 facciamo il suo complemento 0000000001000001 1111111110111111 Vediamo allora quali numeri negativi possiamo rappresentare. Nell‟ipotesi di avere due byte a disposizione per le nostre parole, iniziamo col fare il complemento a 2 dei numeri 1, 2, …. 1 2 3 4 … 0000000000000001 0000000000000010 0000000000000011 0000000000000100 -1 -2 -3 -4 1111111111111111 1111111111111110 1111111111111101 1111111111111100 Come si può osservare, i numeri positivi iniziano con 0, quelli negativi con 1. Inoltre, mentre i numeri positivi crescono, quelli negativi decrescono. Arriviamo fino ai più grandi positivi che possiamo rappresentare su due byte. 32765 32766 32767 0111111111111101 0111111111111110 0111111111111111 -32765 -32766 -32767 1000000000000011 1000000000000010 1000000000000001 Possiamo decrescere ancora con i numeri negativi (mentre per quelli positivi non possiamo più crescere), quindi possiamo rappresentare anche il -32768 con 1000000000000000. In definitiva, con 2 byte a disposizione, possiamo rappresentare tutti i numeri interi da -32768 a 32767. Se avessimo invece parole di un solo byte, potremmo rappresentare tutti gli interi da -128 a 127. In generale, vale la seguente regola: con n bit si possono rappresentare tutti i numeri interi con segno da -2n-1 a 2n-1 -1. Linguaggio C: possono essere definiti i seguenti tipi di dato interi con segno: Tipo di dato short int int numero di byte 2 byte 1 parola, di 2 o 4 byte (il numero dipende dal computer) 4 byte long int intervallo valori ammessi Da -32768 a 32767 … Da -2147483648 a 2147483647 Se in un calcolo succede di arrivare a cifre maggiori o minori di quelle che si possono rappresentare, si dice che c‟è un errore di overflow. Solitamente, in questi casi il programma in esecuzione si blocca, oppure può succedere che vengono semplicemente ignorate le cifre più significative, cioè quelle più a sinistra, causando una perdita di informazione. RAPPRESENTAZIONE DEI NUMERI REALI Iniziamo col dire che non è possibile rappresentare nel computer reali irrazionali come √2 o . Questo perché essi hanno infinite cifre decimali, e servirebbe una memoria infinita per contenerli. Di conseguenza, possono essere rappresentati solo numeri razionali, e nemmeno tutti, solo quelli senza troppe cifre decimali. La rappresentazione che noi umani siamo abituati ad usare è quella in virgola fissa, che prevede di elencare a sinistra della virgola la parte intera, e a destra della virgola la parte decimale. Esempi: 1.5 0.000123 12.01 Il computer invece utilizza una rappresentazione in virgola mobile, o anche detta notazione scientifica. In questa, si distinguono una mantissa e un esponente, e si usa la lettera E per separare le due cose. Il significato del numero è il seguente: mantissaEesponente = mantissa * 10 esponente. Esempi: numero in virgola mobile numero rappresentato numero in virgola fissa 3E-4 3*10-4 0.0003 -12E5 -12*105 -120000 1.4E2 1.4*102 1400 Un numero in virgola mobile può sempre essere scritto in modo che la mantissa abbia un valore assoluto minore di 1, e la prima cifra decimale maggiore di zero. In questo caso, si parla di notazione in virgola mobile normalizzata, e l‟esponente prende il nome di caratteristica (ma molto spesso capita che si evita questa precisazione parlando semplicemente di virgola mobile, mantissa ed esponente). Esempi: virgola mobile normalizzata 3E-4 0.3E-3 12E5 0.12E7 1.4E2 0.14E3 In genere, i reali sono rappresentati su più parole, poiché per essi è richiesta una precisione maggiore che per gli interi. Avendo a disposizione 4 byte, ad esempio, la ripartizione dei bit è come segue: Un bit per il segno (0 se positivo, 1 se negativo) 8 bit per la caratteristica (aumentata di 127, negativa se <127, positiva se >127) 23 bit per la mantissa (lo 0 e la virgola non sono rappresentati) In generale, la rappresentazione avviene secondo la seguente formula, (-1)s × m × 2(e - 127) dove abbiamo indicato il bit di segno con s, la mantissa con m e l‟esponente o caratteristica con e. Se si hanno a disposizione 8 byte, invece, il numero di bit per la mantissa e la caratteristica risulta raddoppiato. Più precisamente, con 8 byte a disposizione abbiamo un bit per il segno, 16 bit per l‟esponente (che risulta aumentato di 32767) e 47 bit per la mantissa. Linguaggio C: possono essere definiti i seguenti tipi di dato reali Tipo di dato float numero di byte 4 byte double 8 byte Intervallo valori ammessi da ±1.40129846432481707e-45 a ±3.40282346638528860e+38 da 2.2250738585072014 * 10 -308 a 1.7976931348623157 * 10 308 Un numero di tipo float si dice in singola precisione, mentre un numero di tipo double è detto in doppia precisione. Questo termine deriva dal fatto che poiché non possono essere rappresentati nel computer i numeri irrazionali (ma nemmeno quelli razionali con troppe cifre decimali), per essi possiamo usare solo un‟approssimazione, che sarà tanto più precisa quante più cifre decimali riusciamo a rappresentare. Ovviamente, con più bit, si possono rappresentare più cifre decimali, quindi, il tipo double risulta molto più preciso del tipo float. RAPPRESENTAZIONE DELLE INFORMAZIONI ALFANUMERICHE Si utilizza la codifica ASCII (American Standard Code for Information Interchange), che prevede di associare un numero su 8 bit a ogni possibile simbolo (lettera, cifra, segno di punteggiatura, caratteri speciali). Quindi, secondo la codifica ASCII, è possibile rappresentare fino a 256 simboli. Ogni simbolo prende il nome di carattere. Essendo un carattere rappresentato su un numero di bit pari a 8, esso può essere rappresentato anche come coppia di cifre esadecimali. I primi 128 codici ASCII sono riportati nella pagina successiva. Per richiamare un particolare carattere conoscendo il suo codice ASCII è possibile premere ALT + numero (sul tastierino numerico). Ad esempio, il carattere „{„ corrisponde a ALT+123, mentre il carattere „}‟ corrisponde a ALT+125 (ci serviranno molto nel linguaggio C). Attualmente, poiché la globalizzazione ha comportato la necessità di comunicare sempre più spesso con persone che usano altri alfabeti, diversi da quello latino (cirillico per i russi, ideogrammi cinesi e giapponesi, ecc.), è stata ampliata la codifica ASCII da 8 a 16 bit, ed ha preso il nome di UNICODE, che prevede la rappresentazione di 65536 simboli diversi. Sequenze di caratteri sono dette stringhe, e vengono rappresentate in modi diversi a seconda dei linguaggi di programmazione. Il Pascal e il Visual Basic, ad esempio, utilizzano il tipo string che può avere un numero qualsiasi di caratteri. Il C, invece, nella sua versione “base”, non prevede un tipo string: le sequenze sono vettori di caratteri (i vettori sono delle particolari strutture dati, che studieremo tra un po‟). Solo il C++ successivamente ha introdotto delle estensioni del linguaggio per supportare tale tipo di dato. Tabella dei codici ASCII Linguaggio C: può essere definito il seguente tipo di dato alfanumerico Tipo di dato unsigned char char numero di byte 1 byte 1 byte Intervallo valori ammessi 0 ÷ 255 -128 ÷ 127 RAPPRESENTAZIONE DEI VALORI BOOLEANI La rappresentazione dei valori booleani dipende dal particolare linguaggio di programmazione. Il Pascal, ad esempio, dispone del tipo boolean e i valori che possiamo assegnare a variabili di questo tipo sono true e false. In C la situazione è diversa: ogni tipo di dato può essere interpretato come booleano, con la convenzione che il valore 0 equivale a falso, e un qualsiasi altro valore diverso da 0 equivale a vero. Esempi: valore booleano 15 vero 0 falso -2 vero 0.18 vero