Scopo della lezione è presentare le modalità di rappresentazione dei numeri utilizzate dalla macchina. Supponiamo di avere a disposizione un insieme di simboli, che chiamiamo alfabeto. Un esempio di alfabeto è l’alfabeto usuale, {A, B, … , Z}. Le macchine utilizzano un alfabeto ridotto composto da soli due simboli, {0, 1}. La relazione che associa ad una particolare combinazione di simboli un particolare dato è detta “codice”. Ad esempio l’insieme ordinato di simboli GATTO codifica l’idea di un animale con quattro zampe, una coda, etc… Il codice mette dunque in relazione le successioni ordinate di simboli con il loro significato. E’ importante notare che non sono solo i simboli utilizzati a codificare per un determinato significato, ma anche il loro ordinamento: la parola GOATT non significa nulla nel codice “lingua italiana”, pur essendo costituita dagli stessi simboli della parola GATTO. I calcolatori utilizzano un particolare alfabeto per la codifica dell’informazione. In particolare, nei calcolatori ogni tipo di informazione è rappresentato in forma binaria. L’alfabeto dei calcolatori è dunque costituito da due soli simboli, per convenzione {0, 1}. Attenzione! 0 e 1 non rappresentano in questo caso due numeri, sono semplicemente i due simboli dell’alfabeto utilizzato (quindi potrebbero essere sostituiti, ad esempio, da {TRUE, FALSE}, {ALTO, BASSO} etc…, senza che cambi il significato della rappresentazione). Avendo a disposizione un singolo bit, è possibile rappresentare 2 stati diversi: 0 e 1. Con due bit, gli stati diventano quattro: 00, 01, 10, 11. Con 3 bit, 8 stati… E’ facile dimostrare che, avendo a disposizione una stringa di n bit, è possibile rappresentare 2n stati diversi. L’alfabeto binario è utilizzato dai calcolatori per rappresentare l’informazione in forma numerica. Ad esempio, il codice ASCII associa ad ogni carattere “a”, “b”, “c”, …, “A”, …, “5”, … etc., un numero compreso tra 0 e 255. In un file di testo troviamo una sequenza di numeri, ciascuno compreso tra 0 e 255, a ciascuno dei quali viene associato un carattere mediante la codifica ASCII. Ogni numero compreso tra 0 e 255 viene rappresentato utilizzando una stringa di 8 bit. Il processo completo per la comprensione di un file ASCII è dunque rappresentato da: leggi 8 bit, es. 01100011 Æ converti in numero decimale, es. 35 Æ identifica il carattere ASCII associato a quel numero, cioè #. In realtà il calcolatore non effettua la conversione binario Æ numero decimale, bensì interpreta direttamente la stringa 01100011 come il carattere # in formato ASCII. Dunque, per riassumere, noi utilizziamo i numeri utilizzando un alfabeto di dieci simboli, {0, 1, …, 9}. Il computer rappresenta i numeri utilizzando un alfabeto di soli due simboli, {0, 1}. Un “Bit” è propriamente una “binary digit”, ovvero una cifra binaria, ovvero una cifra che può assumere solo due diversi valori. Il bit è anche l’unità con cui viene misurato il contenuto di informazione (la quantità di informazione contenuta in un’immagine o in qualche altro tipo di dato può essere quantificata utilizzando il bit come un’unità di misura, ad esempio si può dire che un’immagine contiene 3.4 bit di informazione… Æ teoria dell’informazione di Shannon). L’informazione contenuta in un bit è scarsa: può solo distinguere tra diversi stati. Mettendo insieme 8 bit in una sequenza ordinata è invece possibile ottenere 256 configurazioni diversi. Una sequenza di 8 bit è detta byte. Dunque, con un byte, è possibile rappresentare ad esempio i numeri che vanno da 0 a 255, oppure i numeri che vanno da -127 a 128, oppure un set di 256 caratteri diversi (come avviene nel caso della codifica ASCII). 8 bit è anche la lunghezza tipica delle celle di memoria. I computer sono costruiti per elaborare una quantità minima di informazione pari ad 1 byte. Infatti, si accede alle celle di memoria (che possono essere prelevate, portate nella CPU, elaborate, ricopiate in memoria) utilizzando 1 byte come porzione minima. Att.ne! Questo non significa che il PC non sia in grado, ad esempio, di modificare un singolo bit in memoria; significa che per farlo accede al byte che contiene il bit di interesse, lo porta in CPU, modifica il bit di interesse nel byte, ricopia il byte in memoria. Dunque, nella memoria del computer vengono registrate sequenze di bit – il processore elabora sequenze di bit. Nelle memorie del computer troviamo sequenze di bit. La memoria è organizzata logicamente in celle indirizzabili, cioè: - Una cella contiene un certo numero di bit (sempre lo stesso per tutte le celle); il numero di bit contenuto dalla cella è detto lunghezza della cella; - La cella è indirizzabile, cioè ad ogni cella è associato un indirizzo che permette di accedere al contenuto della cella; - Anche gli indirizzi hanno una lunghezza in bit fissata; la lunghezza massima degli indirizzi determina la dimensione massima della memoria. Ad esempio, se utilizziamo indirizzi di 4 bit, possiamo indirizzare 24 = 16 celle diverse. La massima dimensione della memoria è allora di 16 celle (sarebbe inutile costruire una memoria più grande in quanto una cella non indirizzabile è poco utile!). Per riassumere, sia BC il numero di byte contenuto in ogni cella di memoria (tipicamente, BC = 1, 2). Sia invece bi il numero di bit utilizzati come indirizzo delle celle di memoria (tipicamente bi = 16, …, 64). Il numero massimo di celle di memoria indirizzabili è dato dal numero massimo di combinazioni che si possono ottenere con bi bit, cioè 2bi. La dimensione massima della memoria in byte è allora data dal numero massimo di celle per la dimensione della singola cella, cioè 2bi · BC. Abbiamo già accennato al fatto che, nel calcolatore, la rappresentazione dell’informazione è in forma numerica. Ad esempio, un suono viene rappresentato da una sequenza di intensità in decibel, es. [1, 2, 7, 9, 3, 1, 5, 5] dB (decibel); per rappresentare tali numeri, il computer utilizza il sistema binario, dunque una possibile rappresentazione del suono nel computer sarà data da: [0001, 0010, 0111, 1001, 0001, 0101, 0101] (binario). Un numero è a tutti gli effetti un’entità astratta indipendente dalla sua rappresentazione. Un insieme che contiente quattro elementi ha cardinalità pari a quattro; il numero cardinale “quattro” è dunque il concetto espresso da tutti gli insiemi con cardinalità quattro, ma le rappresentazioni possibili sono varie: quattro, 4, IV, ****, etc… Analizziamo con maggiore dettaglio i diversi modi di rappresentare i numeri. Il sistema di numerazione romano è un esempio di rappresentazione additiva/sottrattiva: Il significato dei simboli che compongono un numero è indipendente dalla posizione in cui compaiono (“I” significa “1”, V significa “5” etc…). L’ordine in cui compaiono i simboli determina il significato additivo / sottrattivo (ad esempio IX per 9, XI per 11). Il sistema posizionale è quello con cui siamo abituati a lavorare tutti i giorni. In Europa il sistema di numerazione arabico è stato introdotto nel Medioevo. E’ basato su una basi di dieci simboli (0, 1, … 9) – si parla di notazione in base dieci. Per notazione posizionale si intende il fatto che il valore di ogni cifra dipende dalla sua posizione nella successione di simboli che rappresenta il numero. Ad esempio, nel numero 1234 la cifra 3 indica “30”, nel numero 3421 la cifra 3 indica “3000”. Per passare dalla rappresentazione di un numero al suo significato utilizzando la notazione posizionale si opera come segue: 1735 = 1·103 + 7·102 + 3·101 + 4·100. In generale, per un numero composto di n cifre si ha che: cn–1 cn–2 ...c1 c0 = cn–1·10n–1 + cn–2·10n–2 + … + c1·101 + c0·100. Si chiamano cifre piú significative quelle associate ai pesi maggiori. La cifra cn–1 è la piú significativa e c0 è la cifra meno significativa. La notazione posizionale è facilmente estendibile al caso in cui la base sia composta da un numero di simboli diverso da dieci. Ad esempio, il computer ha a disposizione i soli due simboli {0, 1}, dunque utilizza un sistema posizionale binario. Dal momento che la rappresentazione in binario può risultare dispendiosa in termini di spazio, sono spesso utilizzati anche il sistema in base 8, con simboli {0, 1, … 7}, ed il sistema in base sedici, con simboli {0, 1, …, 9, A, B, …, F} per ottenere delle rappresentazioni più compatte. Se consideriamo un sistema in base B, abbiamo a disposizione le cifre da 0 a B-1. Mediante una stringa di n cifre in base B è possibile rappresentare Bn numeri naturali, ad esempio quelli che vanno da 0 a Bn-1. Se consideriamo la stringa di cifre cn cn–1 ...c1 c0 in base B, avremo: cn cn–1 ...c1 c0 = cn·Bn + cn–2·Bn–1 + … + c1·B1 + c0·B0 = Σi=0...n ci·Bi Ad esempio: 7058 = 7x82 + 0x81 + 5x80 = 45310, dove il pedice indica la base che viene utilizzata per la rappresentazione del numero. La rappresentazione posizionale presenta alcune proprietà notevoli: 1) un 1 seguito da n 0 rappresenta il numero Bn. (Es. base 10: 100000 = 105; base 2: 100000 = 25). 2) n cifre “massime” rappresentano il numero Bn-1 (base 10: 99999 = 105 – 1; base 16: FFFFF = 165 – 1). E’ possibile per un numero passare dalla rappresentazione in una base ad un rappresentazione in una base diversa mediante l’applicazione di alcune regole. La definizione già data permette di passare dalla base B alla base 10: cn cn–1 ...c1 c0 = cn·Bn + cn–2·Bn–1 + … + c1·B1 + c0·B0 = Σi=0...n ci·Bi (1) applichiamola ad alcuni esempi: In questo modo riusciamo a convertire un numero da base B a base 10. Soffermiamoci per un attimo sulla base binaria, che è utilizzata dai calcolatori. Sappiamo che utilizzando n cifre per rappresentare un numero in base B, possiamo esprimere ad esempio tutti i numero interi che vanno da 0 a Bn-1. Dunque, con n bit possiamo esprimere 2n numeri naturali, quelli che vanno da 0 a 2n-1. E’ pratica comune utilizzare 32 bit per la rappresentazione dei numeri naturali nei calcolatori, dunque il range rappresentabile è: 232–1 = 4,294,967,295 ≅ 4x109 Raddoppiando la lunghezza della stringa utilizzata per la rappresentazione, il massimo numero rappresentabile aumenta esponenzialmente. Ad esempio, utilizzando 64 bit il massimo numero rappresentabile diventerebbe: 264–1 ≅ 1,6x1019 Per passare da un numero in base 2 allo stesso numero in base dieci è sufficiente applicare la definizione cn cn–1 ...c1 c0 = cn·Bn + cn–2·Bn–1 + … + c1·B1 + c0·B0 = Σi=0...n ci·Bi con B=2. Quindi, per fare un esempio: 101100due = (1x25 + 0x24 + 1x23 + 1x22 + 0x21 + 0x20) dieci = (32 + 8 + 4)dieci = 44dieci Abbiamo già detto che altre basi (es. base 8, base 16) vengono utilizzate per comodità di rappresentazione (la base due è troppo dispendiosa per la rappresentazione di grandi numeri su carta!). E’ comodo allora illustrare la procedura generale per passare da una base all’altra. Per fare ciò introduciamo i due operatori div e mod, che rappresentano rispettivamente il risultato della divisione intera tra due numeri ed il resto della stessa divisione. Ad esempio: 5 div 2 = 2, 5 mod 2 = 1 (il che significa che il risultato di cinque diviso due è due con il resto di uno). Se utilizziamo la notazione posizionale in base B, le operazioni di divisione e modulo per B sono particolarmente semplici, infatti: - n mod B è rappresentato dalla cifra c0 meno significativa della rappresentazione di n in base B; - n div B è rappresentato dalle cifre precedenti. Per fare un esempio in base 10: 1537 mod 10 = 7 è rappresentato da 7 1537 div 10 = 153 è rappresentato da 153 La rappresentazione emerge attraverso divisioni intere successive, raccogliendo i resti, che corrispondono alle cifre, partendo da quella meno significativa. Quindi 1537 mod 10 = 7, 1537 div 10 = 153 Æ la prima cifra del numero, quella meno significativa, in base 10, è 7… 153 mod 10 = 3, 153 div 10 = 15 Æ … la seconda cifra del numero, in base 10, è 3 … 15 mod 10 = 5, 15 div 10 = 1 Æ … la terza cifra del numero, in base 10, è 5; … 1 mod 10 = 1, 1 div 10 = 0 Æ … la quarta cifra del numero, quella più significativa, in base 10, è 1. Nel caso precedente abbiamo fatto una conversione da base 10 a base 10, quindi un’operazione praticamente inutile, ma questo è servito per illustrare il processo di costruzione delle cifre di un numero. Lo stesso procedimento viene utilizzato per rappresentare un numero tra due basi diverse. Proviamo ad esempio a convertire lo stesso numero in base 8: 1537 mod 8 = 1, 1537 div 8 = 192 Æ la prima cifra del numero, quella meno significativa, in base 8, è 1…192 mod 8 = 0, 192 div 8 = 24 Æ … la seconda cifra del numero, in base 8, è 0 … 24 mod 8 = 0, 24 div 8 = 3 Æ … la terza cifra del numero, in base 8, è 0; … 3 mod 8 = 3, 3 div 8 = 0 Æ … la quarta cifra del numero, quella più significativa, in base 8, è 3. Dunque, (1537)dieci = (3001)otto; Verifichiamo il risultato applicando la definizione: (3001)otto = (3·83+ 0·82+ 0·81+ 1·80)dieci = (1536 +0 + 0 + 1)dieci = (1537) dieci. Un ultimo esempio: convertire il numero 10 da base 10 a base 2. 10 mod 2 = 0, 10 div 2 = 5 Æ 0 5 mod 2 = 1, 5 div 2 = 2 Æ 1 2 mod 2 = 0, 2 div 2 = 1 Æ 0 1 mod 2 = 1, 1 div 2 = 0 Æ 1 Dunque (10)dieci = (1010)due. Se supponiamo di avere a disposizione una rappresentazione a 6 bit, dobbiamo riempire anche i bit più significativi con degli zero, per ottenere (10)dieci = (001010)due. Come nel sistema decimale normale, infatti, gli zeri posti a sinistra del numero non contano! Avremmo comunque ottenuto lo stesso risultato continuando ad iterare le operazioni di dov / mod fino ad arrivare al sesto bit più significativo. In particolare, ci interessa passare dalla base dieci, con la quale siamo abituati a lavorare, alla base due (notazione binaria), utilizzata dai computer, e viceversa. In base due andremo a definire una rappresentazione per i numeri interi naturali, per gli interi relativi (con modulo e segno, con rappresentazione a complemento, con rappresentazione in eccesso), per i numeri reali… Consideriamo il seguente problema: abbiamo a disposizione celle di memoria di 6 bit. Possiamo rappresentare l’operazione 30+40? La risposta è no, perché con 6 bit riusciamo a rappresentare i numeri da 0 a 26, cioè da 0 a 64. Dal momento che 30+40=70, non abbiamo a disposizione bit sufficienti per rappresentare il numero 70! Si parla in tal caso di errore di overflow. Supponiamo poi di dover effettuare l’operazione 10-20. Come è possibile rappresentare il numero -10? E’ evidente che la notazione che stiamo utilizzando deve essere in qualche modo estesa per tenere conto di questi casi e di altre generalizzazioni (es. numeri con virgola…). Per rappresentare i numeri interi relativi, è possibile impiegare il primo bit della stringa per indicare il segno (0 per +, 1 per ), Gli altri (n-1) bit vengono invece impiegati per rappresentare il valore assoluto del numero. Nella codifica con modulo e segno avremo allora: 0011Æ+3, 0000Æ+0, 1000Æ– 0, 1011Æ– 3. Questa notazione ha il difetto di duplicare la rappresentazione del numero zero, cosa che può complicare l’esecuzione ed il controllo delle operazioni aritmetiche! I numeri rappresentabili vanno da –(2n-1-1) a (2n-1-1), con una doppia rappresentazione per lo zero. Nel calcolatore è la ALU (Unità aritmetico – logica) che si occupa di svolgere i calcoli. In particolare, la ALU si trova nella CPU (parte dei circuiti della CPU costituiscono la ALU). La ALU opera sui dati memorizzati nei registri della CPU. Ma i registri della CPU hanno lunghezza finita (cioè sono costituiti da un numero finito di bit), dunque come non è possibile effettuare calcoli con numeri grandi a piacere! Per poter effettuare i calcoli si utilizza un’aritemtica finita: c’è un numero massimo di cifre binarie disponibili, dunque c’è un numero massimo di numeri rappresentabili… I calcoli effettuati dal calcolatore saranno dunque caratterizzati dal fatto di avere una precisione finita. Per poter trattare i numeri interi con segno si fa ricorso alla notazione a complemento. Per poter trattare numeri “reali”, si fa ricorso alla notazione in virgola mobile. Siccome il numero di cifre massimo è limitato, la precisione raggiungibile nella rappresentazione dei numeri reali è limitata; abbiamo le seguenti precisioni, che spiegheremo poi: semplice (32 bit per numero), doppia (64 bit per numero), estesa (128 bit per numero). Dunque, per riassumere: i calcoli sono svolti dalla ALU, che è una parte della CPU. La ALU impiega i registri della CPU per rappresentare gli operandi. Dal momento che si utilizza una notazione binaria con un numero finito di bit, è necessario utilizzare un’apposita notazione per la rappresentazione dei numeri (a complemento, a virgola mobile). Inoltre, la precisione nella rappresentazione dei numeri reali è finita. Cerchiamo di capire la distinzione tra l’aritmetica usuale e l’aritemica finita. Per fare ciò, pensiamo alla normale rappresentazione dei numeri sulla retta. Man mano che ci si sposta lungo la retta, la rappresentazione dei numeri continua a cambiare, dando luogo a infinite rappresentazioni per infiniti numeri. Con l’aritmetica finita, abbiamo a disposizione un numero finito di rappresentazioni per i numeri. Continuando ad avanzare lungo la circonferenza, si ritorna alla notazione utilizzata per il numero 0! L’orologio analogico è un ottimo esempio di rappresentazione con l’aritmetica finita. Ogni posizione della lancetta dei minuti rappresenta un numero compreso tra 0 e 59. Quando la lancetta arriva alla posizione 59, lo step successivo la riporta alla configurazione corrispondente allo zero (c’è un numero finito di numeri rappresentabili). Introduciamo allora la notazione in complemento: per l’orologio si parlerà di complemento a 60. Con la notazione normale diciamo che sono le 3,15 oppure le 3,45. Con la notazione in complemento a 60, diciamo che sono le 3,15 oppure… Che manca un quarto alle quattro. Quindi, con la notazione in complemento, vogliamo esprimere i numeri positivi e negativi centrati attorno allo zero. In particolare, supponiamo di avere a disposizione una stringa di 3 bit. Sappiamo che, utilizzando tre bit, possiamo esprimere i numeri che vanno da 0 ad 8 utilizzando la notazione convenzionale del sistema binario. Se utilizziamo invece una notazione a complemento, possiamo esprimere i numeri che vanno da -4 a +3 (ovviamente sono sempre 8 i livelli diversi che possono essere espressi). Concentriamoci allora sul sistema binario, e quindi sulla notazione in complemento a due. Con n bit possono essere rappresentati gli interi compresi tra –2n-1 e +(2n-1–1). Esempio: con 4 bit possono essere rappresentati gli interi compresi tra –24-1 e +(24-1–1) cioè tra -8 e +7. Nella rappresentazione in complemento a due, dati n bit, un numero negativo –x si rappresenta con il valore binario corrispondente a 2n-x. Att.ne! Questo modo di operare è diverso dall’utilizzare il primo bit per esprimere il segno (per verificare, si controlli il significato della stringa 100). In particolare, con la notazione in complemente a due, scompare la doppia notazione per lo zero. Il primo bit rappresenta il segno del numero, con lo zero considerato come numero positivo. Supponiamo di dover rappresentare alcuni numeri in complemento a due utilizzando 3 bit. I numeri rappresentabili andranno da -4 a +3. Per i numeri positivi (quelli da 0 a +3) la notazione è analoga a quella binaria. Per i numeri negativi, dovremmo considerare (2n-x), cioè: il numero –x in complemento a due si ottiene come differenza tra 2n e x, dove n è il numero di bit impiegato. Quindi: Per passare dalla rappresentazione in complemento a due al valore reale del numero dovremo applicare la formula inversa, cioè: - se il primo bit è pari a zero, significa che stiamo rappresentano un numero compreso tra 0 e 2n-1-1; la formula di conversione da adottare è quella classica per la conversione da sistema binario a sistema decimale; - se il primo bit è pari a uno, significa che stiamo rappresentando un numero negativo compreso tra -2n-1 e -1; per calcolare il valore del numero, dobbiamo prima convertire da sistema binario a decimale, quindi togliere 2n dal risultato. Esempio: Ma a cosa serve la notazione in complemento a due? A parte il fatto di poter rappresentare i numeri negativi, la notazione serve per semplificare i calcoli, infatti per effettuare la somma tra due numeri (positivi o negativi) non c’è bisogno di fare alcun controllo sul segno! L’operazione di somma e differenza sono eseguibili con la stessa sequenza di operazioni. Dunque anche la circuiteria è semplificata: con lo stesso circuito possiamo fare somma e differenza! Attenzione però: dal momento che l’intervallo di numeri rappresentabili è finito, non tutte le operazioni sono possibili. Ad esempio, se utilizziamo 8 bit per la rappresentazione dei numeri, possiamo utilizzare la notazione binaria convenzionale per rappresentare i numeri tra 0 e 255. Ma cosa succede su cerchiamo di eseguire l’operazione 130+130 = 260? Oppure, utilizzando la notazione in complemento a due, i numeri rappresentabili vanno da -128 a + 127. Cosa succede se cerchiamo di eseguire l’operazione -100 – 200 = - 300? In entrambi i casi si ha un errore di overflow, cioè il risultato dell’operazione non è corretto in quando non rientra nel range dei numeri rappresentabili! Questi errori sono a volte insidiosi: spesso la CPU non controlla che il risulato sia corretto, quindi è possibile che si ottenga il risultato non corretto! Ad esempio, si può ottenere 255 + 1 = 0!!! Questo perché (255)10 = (11111111)2, (1)10 = (00000001)2, il risultato corretto dell’operazione sarebbe (256)10 = (100000000)2, ma siccome usiamo stringhe di 8 bit, il primo bit a sinistra del risultato non viene considerato dalla CPU, e si ottiene dunque (0)10 = (00000000)2!!! Con la notazione in complemento ci si può accorgere facilmente degli errori di overflow. Questi possono accadere solo quando sommiamo due numeri positivi o due numeri negativi. Se si verifica un overflow, la somma di due numeri positivi dà un numero negativo e viceversa. Dunque è sufficiente verificare il bit di segno per capire se c’è stato l’overflow! Abbiamo visto che, con la rappresentazione in complemento a due, siamo in grado di rappresentare numeri interi relativi centrati attorno allo zero. E’ possibile un’ulteriore rappresentazione per i numeri centrati attorno allo zero: si parla allora di rappresentazione in eccesso (o biased). Utilizzando questa convenzione, ad esempio l’intervallo rappresentato [-N ... +(N1)] traslato di +N viene rappresentato dai numeri [0 ... 2N-1] in formato binario. Il valore N è detto eccesso o bias. Ad esempio, usando stringhe di 8 bit, avremo una rappresentazione in eccesso 128. Dunque, per rappresentare il numero x in eccesso, adotteremo la stringa binaria normalmente associata ad (x+128). Quindi 00000000 Æ -128, 00000001 Æ -127, … Abbiamo dunque spiegato come rappresentare numeri interi positivi e negativi. Ma come rappresentare i numeri con la virgola? La prima soluzione possibile è quella di estendere la definizione (1), andando a considerare i numeri dopo la virgola con gli esponenti negativi, cioè: • Rappresentazione con la virgola in base B: cn..c0,c-1..c-k= cnBn + .. + c0B0 + c-1B-1+ .. + c-kB-k • Esempio: 123,45=1x102 + 2x101 + 3x100 + 4x10-1 + 5x10-2 Come per i numeri senza virgola, anche in questo caso per passare dalla notazione in base B alla notazione in base 10 è sufficiente applicare la definizione. Infatti, consideriamo il numero 101,01 in base 2 e calcoliamo il suo valore in base 10: 101,01 = 1 . 22 + 1 . 20 + 1 . 2-2 = 4 + 1 + 1/4 = 5,25 Vediamo allora come è possibile cambiare base per basi arbitrarie e numeri con la virgola. Per la parte intera del numero, si procede come già visto in precedenza (iterando la sequenza di mod e div). Per la parte frazionaria, si procede come segue. Si noti la seguente proprietà: sia 0, c-1c-2..c-k = n ; allora c-1, c-2..c-k = B.n Esempio in decimale: 0,231 . 10 = 2,31 moltiplicando per la base 10 emerge la cifra 2 Per far emergere c-1 basta moltiplicare per B; moltiplicando ancora per B emergerà c-2 e così via… Dunque, se dobbiamo convertire m,n alla base B, prima convertiamo m ottenendo la parte intera in base B; poi, iterativamente, moltiplichiamo n per la base B, nella parte intera di nB troviamo la cifra decimale in che ci interessa in base B… Cioè: pp Si riporta la parte frazionaria della riga precedente Si riporta la parte intera come cifra parte fraz. × base prod. 0,25 ×2= 0,5 0 ×2= 0,5 1,0 Contiene le cifre parte intera binarie, nell’ordine 0 1 ×2= Ci si arresta quando la parte frazionaria si azzera o quando abbiamo un numero di cifre abbastanza elevato 0,25 = 0,01 E’ interessante notare che alcuni numeri sono periodici in una base, ma non in un’altra! Sebbene interessante, la notazione con virgola non è utilizzata nei calcolatori. Bisognerebbe infatti specificare dove è posizionata la virgola. Per capire come vengono rappresentati i numeri con virgola nei calcolatori, introduciamo la notazione scientifica. In notazione scientifica, un numero viene rappresentato come ± m x 10p ,Es. 123.000.000 = 1,23x108. Più in generale, se la base è B, avremo: ± m x Bp Il coefficiente m è detto MANTISSA. Per convenzione, m è un numero in cui la parte intera è composta da una singola cifra (la convenzione è quindi di inserire implicitamente la virgola decimale subito dopo la prima cifra). p è detto CARATTERISTICA, è l’esponente a cui elevare la base B. Abbiamo a questo punto a disposizione tutti gli strumenti per la rappresentazione dei numeri nei calcolatori. La base utilizzata sarà ovviamente la base binaria. Adottando la notazione scientifica possiamo rappresentare numeri con virgola, dal momento che nella mantissa la virgola è sempre posizionata dopo la prima cifra. La regole di conversione sono già state spiegate. La rappresentazione binaria dei numeri reali che usa la notazione scientifica è detta rappre-sentazione in virgola mobile (floating point). Con questa rappresentazione otterremo una precisione diversa a seconda del numero di cifre impiegato per la rappresentazione della mantissa e dell’esponente (dobbiamo sempre ricordare che il numero di bit a disposizione è limitato, dunque il numero di cifre a disposizione per rappresentare esponente e mantissa è limitato e sarà necessario un compromesso sulla precisione). Dunque in notazione scientifica con virgola mobile abbiamo a che fare con numeri del tipo: mEe, dove m è la mantissa, E indica la fine della mantissa e l’inizio dell’esponenziale, e è la caratteristica, dunue mEe = m·Be. Ad esempio, il numero 123.45 si scrive 1.2345E2, cioè 1.2345·102 (Questo per fare un esempio in base 10). Se consideriamo la base 2, avremo per esempio: 101,001 Æ 1,01001 E 10 = (1+2-2+2-5) ·22. Per utilizzare i numeri in virgola mobile nel calcolare, abbiamo bisogno di specificare la dimensione della mantissa e della caratteristica. Tipicamente i numeri in virgola mobile vengono rappresentati nel calcolatore utilizzando una stringa di 32 bit (4 byte) – si parla di rappresentazione in virgola mobile a precisione singola. I 32 bit sono organizzati in ordine come segue: - 1 bit per il segno (0=+, 1=-); - 8 bit per l’esponente, rappresentato in eccesso 127 (dunque i valori per l’esponente andranno da 0 a 255). - 23 bit per la parte frazionaria della mantissa F (la mantissa in toto è 1,F). Per convenzione, il primo numero della mantissa è 1 (si dice che il numero è normalizzato). Adottando questa regola, si evitano rappresentazioni multiple per i numeri! Consideriamo ad esempio la stringa 1 10000100 00100110000000000000000 - Il primo bit è il bit di segno Æ segno meno; - I bit dal secondo al settimo indicano l’esponente in eccesso 127 – (10000100)due = (132)10, dunque l’esponente è 132127 = 5, dunque la parte esoinenziale del numero sarà 25. - I bit dal decimo al trentaduesimo indicano la parte frazionaria della mantissa, dunque avremo 1·2-3+1·2-6+1·2-7; Dunque il numero rappresentato sarà: (2+1·2-3+1·2-6+1·2-7)·25. La rappresentazione esatta di alcuni numeri richiederebbe un numero infinito di cifre, Es. 1/3=0,3333333…, π=3,14159….. Un problema analogo sorge per numeri con valore assoluto molto grande o molto piccolo, in cui il numero di cifre richiesto non sarebbe infinito, ma molto elevato. In questi casi possiamo considerare solo le cifre piú significative. Qualunque sia la codifica scelta, la rappresentazione dei numeri nel calcolatore è soggetta ad approssimazioni. Il limitato numero di cifre disponibili nella mantissa porta ad errori di arrotondamento quando si debbano rappresentare numeri con una mantissa più lunga. Tali approssimazioni si propagano nel corso della esecuzione delle operazioni causando errori numerici anche importanti. Il calcolo numerico è la disciplina che studia le proprietà dell’esecuzione delle operazioni tramite calcolatore e valuta l’entità degli errori introdotti durante l’esecuzione