REPREZENTAREA DATELOR ÎN CALCULATOR
Se stie că un calculator numeric prelucrează numere binare. Acest lucru tine de suportul fizic de manipulare, transport si stocare a datelor interne, mai bine zis este legat de faptul că semnalul fizic purtător de informatie este o tensiune continuă cu două valori: una înaltă (High) si una joasă (Low). Acestor două valori li se asociază natural două valori logice: T (true, adevărat) si F (false, fals) sau cele două cifre binare1 si 0.
Ca urmare a acestei asocieri spunem, prin abuz de limbaj, că un calculator numeric prelucrează numere binare. Ca si un număr zecimal, un număr binar are mai multe cifre binare. Sistemul de numeratie binar folosit pentru reprezentarea informatiei în calculatoare este un sistem de numeratie ponderal, întocmai ca sistemul de numeratie zecimal.
Reprezentarea naturală a numerelor la nivelul perceptiei umane este cea zecimală, pe când reprezentarea proprie masinilor de calcul este cea binară. De aici rezultă necesitatea compatibilizării sau interfatării între aceste două moduri de reprezentare a numerelor. Cum cele două sisteme de numeratie sunt ponderale, o primă diferentă este aceea că sistemul zecimal foloseste ca ponderi puterile întregi (pozitive sau negative) ale lui 10 (zece) iar sistemul binar va folosi puterile întregi (pozitive sau negative) ale lui 2.
În altă ordine de idei, dacă pentru reprezentarea externă sunt semnificative simbolurile de reprezentare (cifre, semnele + sau -, punct zecimal sau binar, mantisă sau exponent), pentru reprezentarea internă sunt necesare conventii de reprezentare: indiferent de tipul datelor, acestea vor fi colectii sau siruri de cifre binare cărora, prin conventie, li se atribuie semnificatii.
Într-o primă instantă, este foarte important să facem o distinctie între tipurile de date recunoscute de un calculator (sau mai bine zis de microprocesorul cu care este dotat calculatorul personal) si formatele de reprezentare ale acestor date ce reprezintă conventii pentru reprezentarea tipurilor de date, atât la nivel intern (în memoria calculatorului) cât si la nivel extern, al perceptiei umane.
Din punctul de vedere al tipurilor de date care sunt implementate în limbajul C putem spune că distingem două mari categorii, date de tip întreg (integer) si date de tip real (float). Formatele de reprezentare internă/externă vor fi prezentate în cele ce urmează. Cel mai simplu de reprezentat sunt numerele naturale. Se face apoi trecerea la numerele întregi negative si apoi la numerele reale care au o parte întreagă si una fractionară.
Reprezentarea internă a numerelor se referă la modul în care se stochează datele în memoria RAM a calculatorului sau în registrii microprocesorului. În acest format se prelucrează numerele pentru implementarea diverselor operatii aritmetice. La nivelul calculatorului informatia nu poate fi decât binară. În această reprezentare putem scrie numere întregi pozitive sau negative sau numere reale.
Există un standard IEEE care reglementează modul de reprezentare internă a datelor.
Reprezentarea externă este reprezentarea numerelor la nivelul utilizatorului uman, deci în principiu se poate folosi orice bază de numeratie pentru reprezentarea numerelor. La nivel de reprezentare externă se foloseste semnul "-" în fata unui număr în cazul în care acesta este negativ sau punctul care separă partea întreagă de cea fractionară. De asemenea, numerele întregi interpretate fără semn se pot afisa si în format binar, octal sau hexazecimal, deci în bazele 2, 8 sau 16.
În cele ce urmează ne vom pune următoarele probleme:
cum se reprezintă extern un număr natural
cum se reprezintă intern un număr natural
cum se reprezintă extern un număr întreg negativ
cum se reprezintă intern un număr întreg negativ
cum se face conversia de la reprezentarea externă la cea internă
cum se face conversia de la reprezentarea internă la cea externă
Reprezentarea externă a numerelor
În ceea ce priveste reprezentarea externă, nu sunt nici un fel de dificultăti deoarece fiecare este familiarizat cu reprezentarea zecimală a numerelor naturale sau reale. Trebuie mentionat de la început că orice tip de reprezentare pe care o vom folosi este ponderală în sensul că pozitia cifrelor în număr nu este întâmplătoare ci conformă cu o pondere corespunzătoare unei puteri a bazei de numeratie.
O caracteristică a reprezentărilor externe este folosirea unor conventii de format unanim acceptate si de altfel foarte naturale pentru un utilizator uman. Spre exemplu, pentru a exprima numere negative se foloseste semnul "-" iar pentru reprezentarea numerelor reale se foloseste punctul "." pentru delimitarea părtii întregi de cea fractionară. De asemenea, suntem familiarizati si cu notatia stiintifică în care intervine mantisa si exponentul (în virgulă mobilă).
Reprezentarea zecimală este cea mai naturală pentru utilizatorul uman. Vom oferi în continuare câteva exemple de reprezentări zecimale externe:
Număr |
Reprezentare normală |
Reprezentare stiintifică |
0.37x102 |
||
-0.37x102 |
||
0.375x100 |
||
-0.375x100 |
||
0.375x10-2 |
||
-0.375x10-2 |
||
0.12375x102 |
||
-0.12375x102 |
În general dorim să obtinem rezultatele numerice ale programelor pe care le concepem într-o formă de reprezentare accesibilă. Totusi, calculatorul trebuie informat asupra formatului de reprezentare în care dorim să se afiseze datele necesare. Aceasta înseamnă că va trebui să specificăm câte cifre se vor folosi la partea întreagă si câte la partea fractionară sau dacă dorim reprezentare stiintifică sau nu. De altfel si operatorul uman face aceleasi conventii de reprezentare. Spre exemplu stim că numărul nu poate fi exact reprezentat ca un număr zecimal, deci fixăm un format de reprezentare. Dacă formatul ale se limitează la 4 cifre zecimale, atunci vom scrie
Limbajul C are o serie de functii de reprezentare cu format a datelor numerice sau alfanumerice prin care programatorul poate impune un format extern cu care se manipulează datele.
Reprezentarea externă a numerelor întregi
Numerele naturale se pot reprezenta fie în baza de numeratie 10, fie în orice altă bază.
În general, un număr întreg în baza b se poate reprezenta cu un număr predeterminat de cifre . Multimea B reprezintă multimea cifrelor sau simbolurilor de reprezentare. Spre exemplu:
Noi suntem obisnuiti să folosim multimea cifrelor zecimale. Dacă totusi se foloseste o bază de reprezentare mai mare decât 10, atunci multimea cifrelor zecimale nu mai este suficientă pentru reprezentarea numerelor în acea bază. Spre exemplu să considerăm baza b = 16 care va folosi 16 cifre hexazecimale (sau mai simplu hexa). Prin conventie, cele 16 cifre hexazecimale vor fi:
Cifra |
Simbol |
Cifra |
Simbol |
A |
|||
B |
|||
C |
|||
D |
|||
E |
|||
F |
Forma generală de reprezentare externă a numerelor întregi este de forma:
Valoarea numerică zecimală a numărului va fi:
În continuare vom studia următoarele probleme:
cum se face conversia unui număr din baza în baza
cum se face conversia inversă, din baza în baza
cum se face conversia dintr-o bază oarecare în altă bază
Pentru a reprezenta un număr natural din baza 10 în baza 2, se împarte succesiv numărul la 2 si se utilizează resturile la aceste împărtiri în ordinea inversă de cum au fost obtinute.
a) Conversia din baza 10 în baza 2 si invers
Fie de exemplu numărul zecimal 37. Reprezentarea sa binară va fi obtinută astfel:
Conversia inversă, din baza 2 în baza 10 este simplă si utilizează ponderea 2:
Cu aceste numere naturale putem face o serie de operatii aritmetice. Adunarea numerelor naturale binare se face întocmai ca la cele în reprezentare în baza 10, după regula:
transport 1 spre rangul următor
Astfel, să facem adunarea 37+25 în binar:
Se observă cum se obtine rezultatul corect.
Înmultirea se face în mod asemănător, ca o adunare repetată. Spre exemplu, să calculăm 37x25
11100111012 = 1x20 + 1x22 + 1x23 +1x24 +1x27 +1x28+1x29 = 1+4+8+16+128+256+512 = 92510
b) Conversia dintr-o bază oarecare într-o altă bază .
Fie spre exemplu numărul care se doreste scris în baza 13.
Pentru a realiza această conversie, vom folosi baza intermediară 10. Vom converti mai întâi în baza 10 si apoi numărul zecimal obtinut îl vom trece în baza 13. Se observă cum un număr în baza 11 poate contine si cifra A=10 iar un număr în baza 13 poate contine cifrele A=10, B=11, C=12.
Reprezentarea externă a numerelor reale
Semnificativă pentru utilizatorul uman este reprezentarea zecimală (în baza b=10) a numerelor reale, cu care suntem obisnuiti. Fată de reprezentarea numerelor întregi, la numerele reale intervine simbolul punct "." care delimitează partea întreagă de partea fractionară. Cu alte cuvinte, cu ajutorul numerelor reale putem reprezenta si numere care nu sunt întregi. Forma generală a unui număr real reprezentat într-o bază oarecare b este:
Valoarea zecimală a numărului de mai sus va fi:
Se observă cum punctul delimitează partea întreagă (exprimată printr-o combinatie de puteri pozitive ale bazei b) si partea fractionară (exprimată printr-o combinatie de puteri negative ale bazei b).
Semnificatie pentru programator si pentru producătorii de software sau microprocesoare au bazele de reprezentare si , deoarece baza 10 este naturală pentru reprezentarea externă a numerelor iar baza 2 este naturală pentru reprezentarea binară, internă, a numerelor.
În formulele de mai sus avem o reprezentare a unui număr real cu n cifre pentru partea întreagă si m cifre pentru partea fractionară.
Asa cum în sistemul zecimal reprezentăm cu un număr finit de cifre zecimale numerele reale, acelasi lucru se va întâmpla si în sistemul binar. Punctul binar va avea o semnificatie asemănătoare cu punctul zecimal, care face separarea între partea întreagă si cea fractionară. Cifrele binare situate după punctul binar vor corespunde puterilor negative ale lui 2.
Astfel, în general, un număr real va avea reprezentarea binară:
Spre exemplu, numărul 12.25 va avea reprezentarea binară:
Partea întreagă a unui număr real se reprezintă binar precum numerele întregi (cu sau fără semn). Pentru a determina partea fractionară, se procedează în mod invers ca la partea întreagă.
Astfel, dacă partea fractionară zecimală se reprezintă binar, atunci aceasta se înmulteste succesiv cu 2. Dacă rezultatul depăseste valoarea 1, atunci se înscrie un bit 1. Se continuă mai departe cu dublarea valorii care depăseste 1. Dacă rezultatul nu depăseste valoarea 1, atunci se înscrie un bit 0 si se continuă multiplicarea cu 2. Spre exemplificare, vom vedeaa cum se obtine reprezentarea binară a lui 12.25. Partea întreagă este 12. Ea se reprezintă binar prin împărtiri succesive la 2 si considerarea resturilor. Partea fractionară este 0.25
Partea fractionară P.F. |
P.F. x 2 |
Noua P.F. |
Bitul înscris |
Obtinem exact rezultatul căutat: 12.25 = 1100.01
Să mai considerăm un alt exemplu. Să reprezentăm numărul 5.37
Partea întreagă are reprezentarea 510 =1012
Partea fractionară P.F. |
P.F. x 2 |
Noua P.F. |
Bitul înscris |
Etc.. |
Etc.. |
Obtinem: 5.3710 = 101.010111101...2
Cu cât mai multe cifre binare vom retine după punctul binar, cu atât vom fi mai aproape de valoarea exactă 5.37.
Obtinem un rezultat foarte important: Desi un număr zecimal poate avea un număr finit de cifre zecimale după punctul zecimal, reprezentarea sa binară internă poate avea un număr infinit de cifre binare. Este valabilă si reciproca: un număr real zecimal cu un număr infinit de cifre se poate reprezenta într-o altă bază pe un număr finit de cifre ( ex: ). Cum orice reprezentare binară internă este pe un număr finit de biti, numărul poate să nu fie reprezentat exact în calculator, ci cu o anumită aproximatie. Acest lucru este decisiv pentru a întelege importanta lungimii reprezentării numerelor în calculator. Cu cât un număr binar se reprezintă pe un număr mai mare de biti, cu atât precizia de reprezentare creste.
2.3 Reprezentarea internă a numerelor
Deoarece semnalul intern purtător de informatie într-un calculator este de tip binar, un număr zecimal (întreg sau real) se va reprezenta intern în baza 2 cu ajutorul unui număr binar. O cifră binară se numeste bit (Binary Digit) si poate fi fie 0 fie 1.
În reprezentarea externă a numerelor am văzut că se poate folosi orice bază de numeratie (cu cifrele corespunzătoare). De asemenea, numerele pot fi prefixate cu un simbol de semn si pot include în reprezentare si punctul de saparatie între partea întreagă si cea fractionară.
În reprezentarea internă acest lucru nu mai este posibil deoarece semnele plus (+), minus (-) sau punct (.) nu au nici o semnificatie pentru calculator. Orice număr (orice tip de dată) este reprezentat la nivel intern de un număr prestabilit de biti. Specialistii din industria software au ajuns la un consens de reprezentare concretizat prin standardul IEEE 754 de reprezentare a internă a numerelor reale în computere.
Reprezentarea internă a numerelor a impus în limbajul C definirea asa-numitelor tipuri de date.
Tipul unei date reprezintă modul în care microprocesorul stochează în memorie si prelucrează cu ajutorul registrilor interni o dată. Tipul unei date se referă la lungimea sa de reprezentare (pe câti biti se reprezintă data) precum si ce semnificatie au anumite câmpuri de biti din cadrul reprezentării.
2.3.1 Reprezentarea internă a numerelor întregi
Un număr binar este o colectie de cifre binare ponderate fiecare cu o putere a lui 2. Bitul corespunzător ponderii celei mai mari, situat cel mai în stânga, se numeste MSB (Most Significand Bit) iar cel corespunzător ponderii celei mai mici, situat cel mai în dreapta, se numeste LSB (Less Significand Bit). În cazul reprezentării binare a numerelor naturale, reprezentarea externă (cea percepută de operatorul uman) si cea internă (cea prelucrată de procesorul calculatorului) sunt asemănătoare. Cum pentru operatorul uman operatorii '+' sau '-' semnifică faptul că un număr este pozitiv sau negativ, este necesară o conventie pentru reprezentarea internă a numerelor întregi negative.
Această conventie prevede folosirea MSB pentru reprezentarea semnului numerelor întregi. Dacă numărul este pozitiv, se adaugă în pozitia MSB bitul de semn '0', iar dacă numărul este negativ se utilizează în pozitia MSB bitul de semn '1'. Mai mult, numerele negative se reprezintă în asa numitul complement fată de 2.
Această formă de reprezentare a numerelor negative necesită parcurgerea următorilor pasi:
pas1. Se reprezintă modulul numărului negativ, folosind bit de semn (egal cu 0, evident)
pas2. Se complementează toti bitii numărului astfel obtinut. Complementarea înseamnă transformarea bitului 0 în bitul 1 si a bitului 1 în bitul 0.
pas3. Numărul astfel obtinut se adună cu 1.
De exemplu, să reprezentăm numărul -37.
pas 1. |-37| = 37
pas2. 0100101---->1011010
pas3. 1011010 + 1 = 1011011 => -3710 = 10110112
Evident, MSB este bitul de semn si este egal cu 1.
La o primă vedere, este posibil să credem că prin utilizarea complementului fată de 2 putem pierde semnificatia numărului negativ. Pentru a vedea ce număr negativ este reprezentat, putem repeta procedeul de mai sus si obtinem reprezentarea numărului pozitiv dat de modulul său.
O modalitate mai simplă este alocarea ponderii corespunzătoare bitului de semn dar pe care o considerăm că reprezintă un număr negativ. Astfel:
0110112 = -1x26 + 1x24 + 1x23 + 1x21 + 1x20 = -64 + 27 = -37
2.3.2 Adunarea, scăderea si înmultirea numerelor întregi
Aceste operatii se execută folosind reprezentarea în complement fată de 2 a numerelor întregi, sau, mai bine zis, se execută folosind în algoritmi bitul de semn ca pe un bit obisnuit.
De exemplu, dorim să calculăm:
(-25)x37
(-25)x(-37)
Pentru efectuarea acestor calcule, vom scrie reprezentările cu bit de semn ale numerelor implicate:
Se observă că 25 si (-25) se reprezintă pe 6 biti iar 37 si (-37) pe 7 biti.
Deoarece am observat că bitii unui întreg cu semn nu au toti aceeasi semnificatie, este nevoie să reprezentăm numerele cu care lucrăm pe un acelasi număr de biti. La adunări sau scăderi, bitii de semn se vor afla în aceeasi pozitie (vor avea aceeasi pondere) si vom obtine astfel rezultate corecte. Pentru a avea o scriere pe un acelasi număr de biti, se adaugă (completează) la stânga bitul de semn de un număr corespunzător de ori. Astfel:
În continuare vom pune în evidentă importanta gamei de reprezentare, adică a domeniului de valori ale datelor. Să considerăm, spre exemplu, adunarea a două numere cu semn reprezentate pe un octet (8 biti). Aceste numere sunt cuprinse în gama
.
Dacă vom dori să adunăm două numere din acest domeniu si să reprezentăm rezultatul tot pe un octet, putem avea surprize. De exemplu, să considerăm operatiile (117-12) si (117+12). Se observă că operanzii sunt în gama de reprezentare a numerelor cu semn pe 8 biti. Prin prima scădere, ne asteptăm să obtinem un rezultat, 105, în aceeasi gamă de reprezentare.
117-12=117+(-12) = 01110101+11110100 = 01101001 = 10510, rezultat corect.
rezultat evident incorect.
Incorectitudinea provine de la faptul că rezultatul a depăsit gama de reprezentare. Dacă rezultatul este interpretat pe 9 biti de exemplu, gama de reprezentare devine si rezultatul va fi
117+12 = 001110101+000001100 = 010000001 = 12910, rezultat corect.
Ca o concluzie preliminară, retinem că pentru a obtine rezultate corecte este necesar să precizăm dacă se lucrează sau nu cu bit de semn si pe câti biti se face reprezentarea, pentru că numai în acest context interpretarea rezultatelor este corectă.
În ceea ce priveste înmultirea numerelor întregi cu semn (cu bit de semn), aici problema nu mai are o rezolvare asemănătoare, în sensul că nu putem trata bitii de semn la fel cu cei de reprezentare ai valorii. Astfel, procesorul studiază bitii de semn si ia o decizie în privinta semnului rezultatului. De fapt, se realizează functia logică XOR a bitilor de semn. Numerele negative se vor lua în modul, iar operatiile de înmultire se vor face numai cu numere pozitive. La final, functie de semnul rezultatului, se ia decizia reprezentării corecte a rezultatului.
Spre exemplu, să calculăm (-25)x37. Pentru aceasta, procesorul va primi pentru procesare următoarele două numere:
Se analizează separat bitii de semn si se ia decizia că rezultatul va fi negativ, deci, la final, se va reprezenta în complement fată de 2. Mai departe se va lucra cu 25, modulul numărului (-25), care se obtine prin complementarea fată de 2 a numărului binar 1100111:
Se va retine pentru procesare numai numărul (fără semn) 11001, care se va înmulti cu numărul (fără semn) 100101, obtinând, asa cum am arătat mai sus, valoarea 1110011101. Mai departe, se adaugă bitul de semn, 0 pentru numere pozitive, obtinându-se 01110011101. Acest ultim număr se va complementa fată de 2, obtinându-se 10001100010+1=[1]0001100011, adică valoarea -1024+99 = -925, valoarea corectă.
Ca o concluzie, pentru a furniza rezultate corecte, procesorul va trebui informat în permanentă despre ce fel de numere prelucrează (cu sau fără semn) si care este lungimea lor de reprezentare (toate trebuie să aibă aceeasi lungime).
Reprezentarea în complement fată de 2 se poate folosi si pentru numerele reale negative, bitul de semn fiind MSB de la partea întreagă. Astfel, -12.25 poate avea reprezentarea:
Pentru înmultirea numerelor reale rămân valabile considerentele de la numere întregi.
În cazul de mai sus, problema reprezentării numărului negativ a fost rezolvată cu ajutorul bitului de semn dar problema reprezentării punctului binar va avea altă rezolvare.
2.3.3 Reprezentarea internă a numerelor reale
Din considerentele de la reprezentarea externă a datelor putem trage alte concluzii importante din punct de vedere al reprezentării interne.
Numerele binare întregi fără semn au aceeasi reprezentare atât externă cât si internă.
Numerele întregi cu semn (care în reprezentare externă sunt prefixate cu ) au ca reprezentare internă un bit de semn, dar care se tratează deosebit de ceilalti biti ai reprezentării. Toti întregii cu semn, care au MSB=1, sunt reprezentati intern în complement fată de 2.
Numerele reale se pot reprezenta identic cu cele întregi cu semn, cu o precizare: nu se face o deosebire netă între bitii reprezentării părtii întregi si cei ai reprezentării părtii fractionare. Acest tratament nediferentiat provine de la reprezentarea stiintifică uzuală cu mantisă si exponent. Fie, spre exemplu, reprezentarea binară a numărului 12.25:
Calculatorul poate reprezenta sirul de biti 110001 si retine faptul că punctul se pune după primii 4 biti ai reprezentării. Acest lucru se întâmplă si în realitate. Deci, singura deosebire între reprezentarea numerelor reale si a celor întregi constă în faptul că numerele reale necesită o informatie suplimentară despre asa numitul exponent, în cazul nostru numărul pozitiv 4.
În cele ce urmează, vom prezenta tipurile de bază pe care le pot avea datele în reprezentarea internă.
Tipul unei date determină modul în care procesorul stochează si prelucrează data respectivă. Cum primele procesoare care au condus la aparitia pe piată a primelor calculatoare pentru neprofesionisti (asa numitele Home Computers) au fost procesoare capabile să prelucreze si să transmită în paralel 8 biti, a fost naturală gruparea a 8 biti într-o entitate numită byte.
1B = 8b (adică un byte reprezintă 8 biti)
Procesoarele au evoluat, ajungându-se în prezent la procesoare pe 64 de biti. Cum evolutia lor s-a făcut trecându-se succesiv prin multipli de 8 biti, s-au impus si alte entităti de reprezentare a informatiei, pe care le vom prezenta sintetic în tabelul de mai jos.
Denumire |
Dimensiune |
Denumire echivalentă |
Notatie |
|||||||
Nr. byte |
Nr. biti | |||||||||
Byte |
1B |
8 b |
octet |
B | ||||||
Word |
2B |
16 b |
cuvânt |
W | ||||||
Double_Words |
4B |
32 b |
Cuvânt dublu |
DW | ||||||
Quad_Words |
8B |
64 b |
Cuvânt cvadruplu |
QW | ||||||
Ten_Words |
10B |
80 b |
TW | |||||||
A determina reprezentarea internă înseamnă să determinăm lungimea reprezentării (de obicei în multipli de octeti), modul de interpretare al bitilor ce compun reprezentarea si gama de reprezentare, adică să determinăm magnitudinea (valorile minime si maxime pozitive si negative) ce pot fi reprezentate în formatul respectiv.
În limbajul C, există două tipuri de reprezentare pe care le putem numi principale: tipul întreg si tipul real, fiecare având si anumite particularizări. Astfel, tipul întreg (int) include si tipul caracter (char) iar tipul real (float) include si tipul real extins (double).
Tipurile de date le vom reprezenta de la simplu la complex, în ordinea char, int, float, double.
Tipurile de bază sunt char, int, float, double si cu ajutorul modificatorilor de tip putem obtine diverse particularizări. Modificatorii pot fi signed, unsigned, short, long.
Ca o generalitate, numerele sunt reprezentate intern luându-se în considerare bitul de semn, deci implicit numerele întregi sau reale au MSB bit de semn. Dacă se specifică explicit, prin modificatorul unsigned, nu se mai consideră (interpretează) bitul de semn.
Tipul char
Codul ASCII (American Standard Code for Information Interchange) este un cod de reprezentare a caracterelor. Prin caracter întelegem unitătile de bază care se pot tasta (intrări de la tastatură), tipări la imprimantă sau afisa pe ecran. Tastatura reprezintă, de exemplu, dispozitivul de intrare care contine de fapt o întreagă colectie de caractere ce pot fi emise prin apăsarea unei taste. Pentru a fi receptat, emis sau prelucrat de către calculator, fiecare caracter are asociat un cod binar (o combinatie de biti) care îl identifică în mod unic. Cum cu un octet putem codifica 28 = 256 caractere, octetul s-a dovedit o entitate suficientă pentru codificarea caracterelor utilizate în informatică. În 256 de coduri distincte se pot include literele mari si mici ale alfabetului anglo-saxon (inclusiv litere specifice diverselor alfabete precum cel chirilic sau particularităti ale diferitelor tări: s, t, â, î, s... în română, de exemplu). Se mai pot include caractere ce reprezintă numere, semne de punctuatie sau alte caractere de control. Codul ASCII a standardizat această codificare, astfel încât el este folosit în cvasitotalitatea calculatoarelor (doar mainframe-urile IBM mai folosesc un alt cod, mai vechi, numit EBCIDIC). Dacă se declară o dată de tip char, ea este considerată explicit de tipul signed char (cu MSB bit de semn), deci reprezentarea internă este de forma:
Gama de reprezentare este cuprinsă între
Dacă se declară tipul unsigned char, atunci nu se mai consideră (interpretează) bitul de semn si data se consideră întreagă pozitivă, în gama
Tabelele de mai sus contin codurile ASCII ale primelor 128 de caractere. Coloana D semnifică valoarea zecimală (decimal) a octetului, coloana H reprezintă aceeasi valoare reprezentată în format hexazecimal (baza 16) iar în coloana Sym se reprezintă simbolul afisat pe monitoarele PC.
Întregul alfabet al limbajului C se regăseste în multimea primelor 128 de caractere ASCII. Restul de 128 de caractere se mai numeste si set de caractere extins ASCII si poate fi vizualizat printr-un program simplu.
Trebuie mentionat faptul că reprezentarea datelor în format hexazecimal este foarte răspândită în tehnica programării calculatoarelor. Avantajul reprezentării interne a datelor în format hexazecimal constă în folosirea unui număr mai mic de cifre (de 4 ori mai mic decât numărul de cifre binare).
Reprezentarea unui număr natural în format hexazecimal se realizează cu metoda împărtirii succesive la 16 sau, mai simplu, pornind de la reprezentarea binară a numărului.
Cum multimea cifrelor hexa contine 16 simboluri (0.9 si A.F), pentru codificarea celor 16 cifre avem nevoie de 4 cifre binare (). Pentru a reprezenta un octet vom avea nevoie de 2 cifre hexazecimale si vom proceda astfel:
se divide octetul în două grupe de câte 4 biti
se înlocuieste fiecare grup de 4 biti cu cifra hexazecimală pe care o codifică.
De exemplu, să presupunem că avem numărul 217.
În acest mod, dacă un număr are o reprezentare internă pe un număr de k octeti, se poate reprezenta simplu cu ajutorul a cifre hexazecimale.
În tabelele de mai jos se prezintă codificarea ASCII a caracterelor.
Codurile corespunzătoare simbolurilor alfanumerice din tabel sunt exact semnalele binare care se transmit în reprezentarea internă. Cu alte cuvinte, dacă la tastatură se tastează simbolul "a", atunci circuitele corespunzătoare transmit spre calculator semnale binare corespunzătoare codului 1010 0001, adică 61H sau 97 în zecimal.
La fel se întâmplă când se lucrează cu procesoare de text sau când se tipăreste un document la imprimantă. Sistemul de calcul manevrează codurile ASCII corespunzătoare literelor si cifrelor pe care utilizatorul le poate interpreta.
D |
H |
Sym |
D |
H |
Sym |
D |
H |
Sym |
D |
H |
Sym |
Null | |||||||||||
" | |||||||||||
| |||||||||||
& | |||||||||||
a |
LF |
1a |
2a |
3a | |||||||
b |
1b |
2b |
3b | ||||||||
c |
1c |
2c |
3c |
< |
|||||||
d |
CR |
1d |
2d |
3d | |||||||
e |
1e |
2e |
3e |
> |
|||||||
f |
1f |
2f |
3f |
D |
H |
Sym |
D |
H |
Sym |
D |
H |
Sym |
D |
H |
Sym |
80 |
P |
96 |
p |
||||||||
A |
81 |
Q |
97 |
a |
q |
||||||
B |
82 |
R |
98 |
b |
r |
||||||
C |
83 |
S |
99 |
c |
s |
||||||
D |
84 |
T |
|
d |
t |
||||||
E |
85 |
U |
e |
u |
|||||||
F |
86 |
V |
f |
v |
|||||||
G |
87 |
W |
g |
w |
|||||||
H |
88 |
X |
h |
x |
|||||||
I |
89 |
Y |
i |
y |
|||||||
4a |
J |
90 |
5a |
Z |
6a |
j |
7a |
z |
|||
4b |
K |
91 |
5b |
6b |
k |
7b | |||||
4e |
N |
94 |
5e |
6e |
n |
7e | |||||
4f |
O |
95 |
5f |
6f |
o |
7f |
Tipul int
Acest tip se foloseste pentru reprezentarea numerelor întregi cu sau fără semn. Odată cu standardizarea ANSI C din 1989, s-a trecut la modul de reprezentare a întregilor impus de noul procesor Intel 80386 dotat si cu coprocesorul matematic Intel 80387.
Tipul int este identic cu signed int si utilizează o reprezentare pe 4B a numerelor întregi cu semn. Reprezentarea pe 4 octeti duce la posibilitatea măririi gamei de reprezentare astfel:
Rezultă că putem reprezenta numere întregi în gama:
unsigned int nu va mai lua în considerare bitul de semn, astfel încât reprezentarea internă este de forma din figura de mai jos. Evident,
Gama de reprezentare se poate schimba cu ajutorul modificatorilor short sau long.
unsigned short int va schimba gama de reprezentare în
long int se va reprezenta pe 8B si va conduce la o gamă imensă de reprezentare a numerelor întregi, lucru dovedit de
unsigned long int va considera numai numere întregi pozitive în gama .
Tipul float
Acest tip de reprezentare este de tip real, fiind cunoscut si ca reprezentare în virgulă mobilă (floating point). Acest tip descrie mecanismul de bază prin care se manipulează datele reale. Conceptul fundamental este acela de notatie stiintifică, prin care orice număr se poate exprima ca un număr zecimal (deci, cu punct zecimal) multiplicat cu o putere a lui zece sau ca un număr real binar (cu punct binar) multiplicat cu o putere a lui 2.
Se observă cum stocarea în calculator a unei date floating-point necesită trei părti:
bitul de semn (sign)
mantisa, fractia (significand)
exponent (exponent)
Folosind formatul specific I80386, în limbajul C se disting trei tipuri de date reale:
float , cu reprezentare pe 4 octeti (32 biti, double word)
double, cu reprezentare pe 8 octeti (64 biti, quad word)
long double, cu reprezentare pe 10 octeti (80 biti, ten word)
Tipurile float si double sunt formate pentru numere reale ce există numai în memorie. Când un astfel de număr este încărcat de procesor în stiva pentru numere reale (flotante) pentru prelucrare sau ca rezultat al prelucrării, el este automat convertit la formatul long double (sau extended).
În cazul în care acest număr se stochează în memorie, el se converteste la tipul float sau double. Toate cele trei subtipuri reale au un format comun, care va fi prezentat în continuare. Ceea ce le deosebeste este numărul de biti alocati pentru exponent si pentru mantisă, precum si interpretarea bitilor mantisei (significand).
Semnul are alocat în toate formatele un singur bit: 0 pentru numere pozitive si 1 pentru numere negative.
Mărimea câmpului exponent variază cu formatul si valoarea sa determină câti biti se mută la dreapta sau la stânga punctului binar.
Câmpul significand este analogul mantisei în notatia stiintifică. El contine totii bitii semnificativi ai reprezentării, deci bitii semnificativi atât ai părtii întregi cât si ai părtii fractionare cu singura restrictie ca acesti biti să fie consecutivi. Deoarece punctul binar este mobil, cu cât sunt mai multi biti alocati părtii întregi, cu atât vor fi mai putini pentru partea fractionară si invers. Cu cât formatul este mai larg, cu atât se vor reprezenta mai precis numerele.
Pentru a salva un spatiu pretios de stocare, nici unul dintre cele trei formate float nu stochează zerouri nesemnificative. De exemplu, pentru numărul câmpul significand va stoca numărul 101, nu si cele 4 zerouri nesemnificative ale părtii fractionare. Pentru a salva si mai mult spatiu, pentru formatele float si double câmpul significand nu va contine primul bit semnificativ care obligatoriu este 1. Câstigând acest bit (numit bit phantom), se dublează gama de reprezentare. Formatul long double va contine totusi bitul de semn 1 cel mai semnificativ. Punctul binar se pune exact înaintea primului bit din câmpul significand, adică după bitul 1 implicit (phantom). În cazul long double, se aplică după primul bit 1.
Pentru a usura operarea cu aceste numere, câmpul exponent nu este stocat ca un număr întreg cu semn, ci este decalat (normalizat, cu bias) pentru a reprezenta numai numere pozitive (deci exponentul este interpretat ca număr natural fără semn). Biasul adăugat se scade pentru a afla exponentul exact. Avantajul exponentului decalat constă,pe lângă faptul că nu mai are nevoie de bit de semn, în faptul că pentru a compara două numere reale putem începe prin compararea bitilor pornind de la MSB către LSB, cel mai mare fiind cel care are 1 la primul bit diferit. Se decide astfel foarte rapid care număr este cel mai mare. Ca exemplu, să considerăm un format float în care se stochează:
Sign
Exponent
Significand
Valoarea reală a exponentului va fi 130 - 127 = 3
Bitii câmpului significand se obtin adăugând MSB phantom, deci acestia vor fi 11001000...00
Numărul real care s-a stocat este:
0.110010...00 x 24 = 1100.1 =12.5
Reprezentarea internă a numărului 12.5, pe 4 octeti (float), este următoarea:
Cu alte cuvinte, putem spune că reprezentarea internă a numărului real 12.5 este (în format hexazecimal):
În cazul în care dorim să reprezentăm numărul negativ -12.5, singurul bit care se va modifica va fi bitul de semn, care devine 1. Astfel, reprezentarea internă în format float a numărului negativ real -12.5 este:
Dacă numărul 12.5 se reprezintă în formatul double, deci pe 8 octeti, atunci reprezentarea sa internă se va realiza astfel:
bitul de semn va fi 0
exponentul nu va mai fi pe 8 biti ca la tipul float, ci pe 11 biti, deci se va schimba si bias, care va fi 1023. Atunci:
significand va fi acelasi ca la tipul float, dar reprezentat pe 52 de biti
Retinem că la numere reale numai bitul de semn indică dacă numărul este pozitiv sau negativ, mantisa si exponentul se reprezintă ca numere naturale fără bit de semn. Formatele prezentate mai sus respectă standardul IEEE 754 de reprezentare a internă a numerelor reale în computere.
Se poate pune o întrebare legitimă: de ce bias-ul în cazul float spre exemplu este 127? Pentru a răspunde la această întrebare, putem face următorul rationament:
exponentul cu semn este reprezentat pe 8 biti, deci este în gama de reprezentare .
pentru a obtine un exponent pozitiv, adăugăm numărul 128.
deoarece bitul phantom nu este reprezentat, exponentul trebuie micsorat cu o unitate pentru a indica unde anume se pozitionează exact punctul binar.
Exponent pozitiv = exponent +128 - 1 = exponent + bias
de unde rezultă evident faptul că bias = 127 în cazul tipului float.
În final să analizăm un exemplu de procesare a produsului a două numere reale. Vrem să calculăm valoarea 5.25 x 1.5. Pentru aceasta, vom scrie cei doi factori ai produsului în forma:
Se observă cum câmpurile exponent si significand sunt procesate separat, în final corelându-se forma de reprezentare internă.
Gama de reprezentare pentru fiecare din tipurile reale prezentate mai sus se calculează luând în considerare cel mai mare număr si cel mai mic număr posibil a fi scris în respectiva reprezentare. Astfel, exponentul este decisiv pentru gama de reprezentare.
La tipul float, avem
Valoarea maximă exactă, calculată fără a aproxima ca mai sus:
este
Valoarea pozitivă minimă exactă este
La tipul double vom obtine:
Valoarea maximă exactă este
Valoarea pozitivă minimă exactă este
Efectuând aceleasi consideratii si calcule pentru tipul long double, vom obtine
Codificare BCD
Procesorul I80386 este considerat primul procesor care are capacitatea de a procesa operatii aritmetice asupra unor numere reprezentate în zecimal codificat binar (BCD, binary-coded decimal) în locul formatelor binare standard. Reprezentarea numerelor în cod BCD este folosită pentru a face numerele binare mai accesibile operatorului uman. Neajunsul acestei reprezentări este faptul că numerele BCD ocupă spatiu de stocare mai mare decât numerele binare. Ele sunt mai usor de interpretat de către programatorul uman, pentru computer neavând nici un fel de relevantă. Procesorul 80386 poate manevra două tipuri de formate BCD: înpachetat si neînpachetat (packed BCD si unpacked BCD). În formatul unpacked BCD, o cifră zecimală se stochează pe un octet. Spre exemplu, cifra zecimală 5 va fi reprezentată intern sub forma 00001001. Formatul packed BCD stochează două cifre zecimale pe un octet, crescând capacitatea de stocare internă precum si gama de reprezentare pe un acelasi număr de octeti. Ambele codificări folosesc reprezentarea pe 4 biti a cifrelor zecimale. Spre exemplu, numărul 9817 se stochează pe 4 octeti în format unpacked BCD si pe 2 octeti în format packed BCD:
unpacked BCD:
packed BCD 9817 = 1001 1000 0001 0111
Se observă cum valoarea maximă care se poate stoca pe un octet este 9 pentru unpacked BCD, 99 pentru packed BCD si 255 pentru codificarea binară fără semn standard.
Toate formatele reale prezentate se conformează standardului IEEE 754 pentru reprezentarea numerelor în virgulă mobilă în format binar.
Ca o concluzie la acest capitol, decisiv pentru întelegerea dezvoltărilor ulterioare, putem sintetiza următoarele:
Reprezentarea externă a numerelor se referă la modul în care operatorul uman acceptă schimbul de date cu calculatorul. Acest schimb de date are dublu sens: de la operatorul uman către calculator si invers.
Reprezentarea externă este de obicei zecimală si are un format aproape identic cu formatul matematic uzual: simbol de semn prefixat, punct zecimal, mantisă sau exponent. Numerele naturale se mai pot reprezenta si în format octal sau hexazecimal. În format extern se introduc datele de la tastatură pentru prelucrare si se obtin pe monitor sau la imprimantă rezultatele oferite de calculator.
Reprezentarea internă a numerelor se referă la modul în care se stochează datele în memoria RAM a calculatorului si respectiv în registrii interni ai microprocesorului. Această reprezentare internă este legată de notiunea de tip de dată.
Tipul de dată întreg (integer) se reprezintă intern pe 2, 4 sau 8 octeti în complement fată de 2, cu cel mai semnificativ bit (MSB) bit de semn: 1 pentru numere întregi negative si 0 pentru numere întregi pozitive. Un caz particular de dată de tip întreg este tipul character, interpretat ca întreg pe un octet.
Tipul de dată real (float) se reprezintă intern pe 4, 8 sau 10 octeti si contine 3 câmpuri de biti distincte: bit de semn, câmp mantisă si câmp exponent, de lungimi corespunzătoare.
Dacă se specifică explicit, toate numerele se pot defini fără semn (unsigned), caz în care calculatorul nu mai interpretează bitul de semn (MSB) diferit ci îl include în câmpul de reprezentare al mărimii, crescând gama de reprezentare.
|