Sunteți pe pagina 1din 241

CUPRINS

PREFAŢĂ ---------------------------------------------------------- 3

1 INTRODUCERE ----------------------------------------------- 5
1.1 Calculator şi informatică------------------------------ 5
1.2 Utilizarea sistemelor de calcul ----------------------- 6
1.3 Principii de funcţionare ------------------------------- 9

2 MODELE DE DATE ÎN SISTEMELE DE CALCUL ------ 12


2.1 Reprezentarea informaţiei ------------------------------ 12
2.2 Coduri de erori ------------------------------------------- 21
2.3 Elemente de logică numerică -------------------------- 36
2.4 Memorii ------------------------------------------------- 44
2.5 Unitatea centrală de prelucrare ------------------------ 47
2.6 Unităţile de intrare/ieşire ------------------------------- 57

3 SUPERCALCULATOARE ŞI MICROPROCESOARE ---- 63


3.1 Supercalculatoare ---------------------------------------- 63
3.2 Paralelism ------------------------------------------------ 67
3.3 Microprocesoare ----------------------------------------- 68

4 ELEMENTE DE TELEINFORMATICĂ --------------------- 71


4.1 Transmisia informaţiilor -------------------------------- 72
4.2 Reţele de calculatoare ----------------------------------- 75

5 ELABORAREA PROGRAMELOR ---------------------------- 82


5.1 Limbajul de asamblare ---------------------------------- 84
5.2 Limbaje de programare --------------------------------- 89
5.3 Etapele dezvoltării unui program---------------------- 98

6 STRUCTURI DE DATE ----------------------------------------- 105


6.1 Tipuri şi structuri----------------------------------------- 105
6.2 Fişiere şi baze de date ----------------------------------- 110
7 SISTEME DE OPERARE ---------------------------------------- 113
7.1 Evoluţie şi caracteristici -------------------------------- 113
7.2 Structura unui sistem de operare modern ------------ 117

8 SISTEMELE DE OPERARE ACTUALE --------------------- 145


8.1 Sistemul DOS--------------------------------------------- 146
8.2 Sistemele Windows -------------------------------------- 163
8.3 Sistemul UNIX ------------------------------------------- 170

9. APLICAŢII JAVA ------------------------------------------------ 179


9.1 Conversie din zecimal în binar, octal, hexazecimal -- 179
9.2 Reprezentări externe ale unui număr întreg---------- 182
9.3 Suma a două numere în baza p ------------------------ 185
9.4 Diferenţa a două numere în baza p ------------------ 189
9.5 Produsul a două numere în baza p -------------------- 193
9.6 Conversia în zecimal a unui număr
reprezentat în baza p ------------------------------------ 197
9.7 Conversia unui număr zecimal în baza p ------------- 201
9.8 Construirea unui careu magic de ordin impar ------- 205
9.9 Conversie din sistemul roman în sistemul arab ----- 207
9.10 Conversie din sistemul arab în sistemul roman ----- 209
9.11 Numere de trei cifre egale cu suma
cuburilor cifrelor lor ------------------------------------- 211
9.12 Conversia unui număr fracţionar
din baza p în baza q ------------------------------------- 212
9.13 Controlul bitului de paritate --------------------------- 217
9.14 Codul lui Hamming pentru emisie mesaj ------------ 219
9.15 Codul lui Hamming pentru recepţie mesaj ----------- 222
9.16 Fişiere în Java -------------------------------------------- 225
9.17 Eliminare spaţii excedentare şir de caractere -------- 227
9.18 Conversie din reprezentare externă în VMSP ------ 230
9.19 Conversie din VMSP în reprezentare externă ------ 234
9.20 Linie de lungime maximă într-un fişier text -------- 237

BIBLIOGRAFIE SELECTIVĂ ------------------------------------ 239

2
PREFAŢĂ

Cunoaşterea mecanismelor esenţiale ale funcţionării sistemelor de calcul


oferă posibilitatea unei aprecieri asupra evoluţiei spectaculoase a domeniului
informaticii.
Aceasta presupune studiul aprofundat al arhitecturii sistemelor de calcul,
atât la nivelul structurii materiale cât şi la nivelul elaborării produselor de
programare, deoarece aceste elemente, ca şi evoluţia lor, sunt intim legate.
Deşi tehnologia construcţiei sistemelor de calcul a evoluat fantastic în
ultimii ani, principiile fundamentale care stau la baza construcţiei acestora
sunt aceleaşi ca şi acum câteva zeci de ani, când informatica abia se
cristaliza ca ştiinţă.
Funcţionarea unui calculator are ca suport matematic o serie de concepte
aritmetice şi algebrice simple: cele patru operaţii aritmetice, noţiunea de
funcţie, elemente ale calculului propoziţiilor etc.
Suportul electronic al unui sistem de calcul are la bază materializarea
fizică a cifrelor binare 0 şi 1, iar la nivelul imediat superior circuitele logice
care materializează fizic operaţiile logice elementare.
Lucrarea este structurată pe 9 capitole.
Capitolul introductiv defineşte contextul şi evoluţia sistemelor de
calcul, schiţează o parte a conceptelor cheie utilizate în informatică şi
prezintă principiile funcţionării sistemelor de calcul.
Capitolul al 2-lea realizează o prezentare a modelelor de date ale
sistemelor de calcul, insistând asupra codificării şi reprezentării diverselor
tipuri de informaţii, coduri de detectare şi uneori chiar de corectare a erorilor
de transmisie.
Este studiată aici problematica bazelor de numeraţie: reprezentarea
numerelor într-o anumită bază de numeraţie şi conversii între diverse baze,
cu un accent deosebit pe bazele 2, 8 şi 16, ca baze de largă utilizare în
informatică.
Sunt descrise de asemenea principalele concepte de logică matematică,
domeniu important nu numai pentru modelarea raţionamentului ci şi ca
instrument de concepţie al circuitelor sistemului şi ca model de calcul pentru
unele limbaje de programare.
Acest capitol detaliază aspectele importante cu privire la componentele
de bază ale arhitecturii unui sistem de calcul clasic.
Capitolul al 3-lea prezintă noţiuni despre supercalculatoare, procesoare
vectoriale şi maşini paralele, conceptul de paralelism, arhitectura de bază a

3
microcalculatoarelor, calculatoarelor personale, profesionale şi a staţiilor de
lucru.
Capitolul al 4-lea descrie câteva elemente de teleinformatică. În acest
context sunt prezentate conceptele de bază ale realizării transmisiei
informaţiei, moduri de transmisie, evoluţia şi principalele caracteristici ale
reţelelor de calculatoare şi tendinţele de standardizare în acest domeniu.
Capitolul al 5-lea se referă la arhitectura software a sistemelor de
calcul. Sunt prezentate aspectele comparative ale limbajului de asamblare şi
limbajelor de programare evoluate precum şi etapele dezvoltării unui
program într-un sistem de calcul.
Capitolul al 6-lea este dedicat prezentării succinte a structurilor de date,
cu referire la principalele tipuri şi structuri, fişiere şi baze de date.
Capitolul al 7-lea prezintă evoluţia, caracteristicile şi structura unui
sistem de operare modern.
Capitolul al 8-lea evidenţiază modalităţile de implementare a
conceptelor şi noţiunilor prezentate în cadrul capitolului al 7-lea pentru
realizarea sistemelor de operare DOS, Windows şi UNIX, care sunt printre
cele mai reprezentative din noua generaţie de sisteme.
Capitolul al 9-lea face referire la implementarea principalilor algoritmi
de reprezentare a informaţiilor în calculator, implementarea structurilor de
date şi câteva aplicaţii diverse. Aplicaţiile practice sunt realizate în limbajul
Java.
Lucrarea se încheie cu o bibliografie relativă la tema propusă.
Deoarece limba engleză este preponderent utilizată în informatică, am
menţionat termenii cei mai importanţi între paranteze drepte.
Cartea este suficient de detaliată şi prezintă într-un mod progresiv de la
simplu la complex noţiunile abordate, încât permite oricărei persoane, chiar
fără cunoştinţe preliminare, să se iniţieze în informatică.
Cartea se adresează în primul rând studenţilor de la secţiile cu profil
informatic din instituţiile de învăţământ superior, precum şi cadrelor
didactice şi elevilor din învăţământul preuniversitar care vizează iniţierea în
informatică sau aprofundarea anumitor noţiuni din acest domeniu.

4
1 INTRODUCERE

1.1 Calculator şi informatică


Termenul englez computer a avut iniţial semnificaţia calculator
numeric electronic, deoarece primele maşini de calcul erau destinate în
special efectuării operaţiilor aritmetice.
În accepţiunea actuală un sistem de calcul este capabil să achiziţioneze şi
să păstreze informaţii, să efectueze prelucrări şi să restituie informaţiile
stocate în vederea utilizării acestora.
Vom utiliza termenul de informaţie cu sensul de „date” de un anumit tip
(valori numerice, texte, imagini, sunete).
Informatica computer science, informatics (termen rezultat din
concatenarea prescurtată a informaţiei şi automaticii) este ştiinţa prelucrării
informaţiei.
Un sistem informatic este o mulţime de instrumente de programare
software şi materiale hardware destinate satisfacerii necesităţilor
informatice ale utilizatorilor.
De obicei, un sistem de calcul este văzut doar în sensul material al
termenului hardware, dar este de notat faptul că un calculator fără software-ul
său este total inutil; noţiunile de hardware şi software sunt inseparabile.
Specialiştii în sisteme de calcul au identificat, utilizând criterii
temporale, tehnologice şi de dezvoltare mai multe generaţii, şi anume:
a) Generaţia I-a, specifică anilor ‘50, se bazează pe tehnologia
tuburilor electronice sub vid, cu memorii pe tambur magnetic,
utilizează limbaj de asamblare şi se caracterizează printr-o
fiabilitate foarte scăzută a calculatoarelor, o capacitate de memorie
şi o viteză de calcul reduse.
b) Generaţia a II-a, specifică anilor ‘60, se bazează pe înlocuirea
tuburilor electronice sub vid cu tranzistorii, memoriile utilizează
tuburi de ferită, limbajele de programare sunt de nivel înalt
(Fortran, Cobol etc.), iar fiabilitatea, capacitatea memoriei precum
şi viteza de calcul cresc considerabil.
c) Generaţia a III-a, specifică anilor ‘70, se bazează pe tehnologia
circuitelor integrate, memorii pe semiconductoare, discuri magnetice,
limbaje de programare de foarte înalt nivel (Pascal, Lisp, limbaje
grafice), capacitate de memorie de ordinul megaocteţilor şi viteze de
calcul de ordinul milioanelor de instrucţiuni pe secundă.

5
d) Generaţia a IV-a, specifică anilor ‘80, se caracterizează prin
utilizarea circuitelor integrate pe scară largă şi foarte largă, memorii
cu bule, discuri optice, limbaje de programare evoluate (Ada,
limbaje orientate obiect), memorii de mare capacitate, viteze de
calcul considerabile, apariţia supercalculatoarelor.
e) Generaţia a V-a, specifică anilor ‘90, are drept caracteristici
importante utilizarea circuitelor integrate pe scară extrem de largă,
utilizarea maşinilor Lisp şi Prolog, a arhitecturilor paralele,
programarea în limbaje concurente, limbajul natural, limbaje
funcţionale (Lisp) şi logice (Prolog), performanţele relative la
memorie şi viteza de calcul făcând posibilă memorarea şi
prelucrarea cunoştinţelor (inteligenţa artificială).
Arhitectura unui sistem de calcul se referă la descrirea unităţilor sale
funcţionale şi interconexiunile dintre acestea.
Configuraţia unui sistem de calcul corespunde organizării adoptate pentru
a asambla şi a face să funcţioneze diversele entităţi materiale (procesoare,
memorie, terminale, imprimante, unităţi de disc etc.) ale sistemului.

1.2 Utilizarea sistemelor de calcul


Utilizarea unui sistem de calcul presupune execuţia programelor pentru
realizarea unor aplicaţii complexe (de exemplu, rezervarea biletelor de
călătorie, gestiunea conturilor bancare, prelucrarea textelor etc.).
Funcţiunile de bază al unui sistem de calcul sunt realizate prin
intermediul programelor sistem dezvoltate în general de către constructor
(de exemplu sistemul de operare).
Programele de aplicaţie sunt elaborate în general de către firme
producătoare de software sau chiar de către utilizatorii sistemului de calcul.
Sistemul de operare operating system, cel mai important dintre
programele sistem, este însărcinat cu gestionarea şi controlul diverselor
resurse ale sistemului de calcul, fiind în general specific unei familii de
calculatoare compatibile. Sistemul de operare coordonează activitatea
utilizatorilor, realizând înlănţuirea etapelor necesare execuţiei unui program
şi oferind un acces simplificat la resursele sistemului de calcul.
Varietatea aplicaţiilor programate pe un sistem de calcul impune
specializarea acestora. Se pot distinge trei mari tipuri de aplicaţii care
solicită sisteme de calcul particulare:
a) calculul ştiinţific, care necesită sisteme cu posibilităţi de calcul
foarte importante asupra numerelor reale în virgulă mobilă sau
asupra vectorilor (de exemplu, supercalculatoarele). Aceste sisteme
de calcul utilizează mari biblioteci de subprograme pentru calculele

6
matematice uzuale (statistică, calcul matricial, calcul integral şi
diferenţial etc.).
b) gestiunea economică, care necesită capacităţi de memorare şi de
prelucrare a unui volum mare de informaţii, structurate în înregistrări
care se găsesc în fişiere stocate pe discuri sau benzi magnetice. O
abordare mai sofisticată a gestiunii informaţiilor constă în a utiliza
sisteme de baze de date, care asigură stocarea înregistrărilor şi
accesarea acestora, permiţând interogări destul de complexe.
c) conducerea proceselor, care necesită în general sisteme de calcul
sau procesoare specializate în achiziţionarea datelor şi controlul în
timp real al aparatelor de o oarecare complexitate (de exemplu,
unităţi industriale, maşini de spălat, carburatoare de maşini etc.).
Se pot distinge de asemenea mai multe moduri de funcţionare ale unui
sistem de calcul:
a) pe loturi de lucrări batch, prin care sistemul de calcul execută în
mod secvenţial un lot de programe, fără a permite interacţiunea cu
utilizatorul;
b) timp partajat time sharing, prin care sistemul de calcul oferă
utilizatorului „iluzia” prelucrării mai multor programe simultan,
datorită posibilităţii de a aloca mici tranşe de timp fiecărui
program al utilizatorului. Aceste sisteme interactive sunt cele mai
apropiate de utilizatori, deoarece aceştia pot dialoga cu sistemul
de calcul într-un anumit limbaj de comandă, cu ajutorul unui
terminal (ecran + tastatură). Sistemele tranzacţionale stabilesc o
colaborare între sistemele conversaţionale şi sistemele de
gestiune care coordonează accesul la mari baze de date;
c) timp real real time, prin care timpul de răspuns al sistemului de
calcul la diferite solicitări joacă un rol important, fiind un factor critic.
Sistemele care asigură conducerea proceselor funcţionează în general
în timp real (de exemplu, comenzile electronice ale unui avion).
Programarea este activitatea care constă în a scrie o secvenţă de
instrucţiuni într-un anumit limbaj înţeles de către sistemul de calcul. Mai
general vorbind, programarea constă în următoarele: pornind de la o
problemă dată să se realizeze un program a cărui execuţie să conducă la o
soluţie satisfăcătoare a problemei puse.
Activitatea de programare se descompune în mai multe faze, care
constituie ciclul de viaţă al unui software:
a) enunţul şi înţelegerea problemei;
b) specificarea (descrierea funcţionalităţilor sistemului);

7
c) concepţia (descompunerea modulară a problemei în subprobleme,
elaborarea algoritmilor etc.);
d) programarea (faza de codificare a programului);
e) testarea şi validarea (se verifică dacă programul realizează, fără
erori, funcţionalităţile specificate);
f) întreţinerea (asigurarea actualizărilor necesare pe întreaga durată a
exploatării).
O fază foarte importantă este cea de asigurare a documentaţiei tehnice
necesare şi ea se efectuează în paralel cu toate celelalte faze.
Un algoritm este o succesiune de acţiuni (instrucţiuni) destinate
rezolvării unei probleme într-un număr finit de operaţii.
Primele programe erau scrise în limbaj maşină (cod binar pur), apoi s-a
utilizat limbajul de asamblare care are avantajul folosirii mnemonicelor şi
simbolurilor.
Limbajele de programare evoluate cum ar fi Fortran, Pascal,
Modula-2, Ada, C, C++ (limbaje ştiinţifice), şi Cobol, PL/I (limbaje de
gestiune) au permis dezvoltarea unor mari produse software.
Limbajele Lisp şi Prolog sunt limbaje ale inteligenţei artificiale care
permit realizarea sistemelor expert şi a căror caracteristică principală este
realizarea simulării inteligenţei umane.
Un program este constituit din diverse tipuri de instrucţiuni care pot
realiza următoarele operaţii:
a) operaţii de intrare / ieşire I/O: Input/Output: de exemplu,
trimiterea unui caracter spre o imprimantă, spre un ecran, într-un
fişier memorat pe disc sau citirea de pe suport magnetic;
b) operaţii de calcul aritmetic: +, -, , /, ...
c) operaţii de calcul logic: and, or, not;
d) operaţii de salt: fie condiţionat, ca de exemplu instrucţiunea clasică
If …Then … Else (aceste operaţii sunt importante deoarece permit
parcurgeri de drumuri diferite în funcţie de rezultatul comparărilor şi
deci de a simula o anumită inteligenţă), fie necondiţionat, de
exemplu apelul unui subprogram.
Un program scris în limbaj evoluat există sub forma unui cod sursă. Pentru a
putea fi executat pe un sistem de calcul, acest cod sursă parcurge următoarele
etape: compilarea, editarea de legături şi încărcarea în memoria centrală.
Compilatorul este un program care transformă un modul în cod sursă
într-un modul în cod obiect (cod maşină).
Editorul de legături este programul care asigură „legarea” diferitelor
module ale unui program cum ar fi subprograme, module din biblioteca
sistemului etc.

8
Încărcătorul este destinat transferării unui program complet şi gata de
execuţie din memoria auxiliară în memoria centrală.
1.3 Principii de funcţionare
Un sistem de calcul se compune dintr-o memorie centrală, care conţine
programele şi datele, o unitate centrală de prelucrare care execută un
program încărcat în memoria centrală, unităţi de intrare / ieşire care permit
schimbul de informaţii cu unităţile periferice. Vom numi unitate centrală
ansamblul constituit din unitatea centrală de prelucrare şi memoria centrală.
Execuţia unui program se derulează potrivit următorului model:
a) programul şi datele aferente sunt încărcate în memoria centrală;
b) instrucţiunile programului sunt aduse secvenţial unităţii de control
care le analizează şi declanşează prelucrarea corespunzătoare,
trimiţând în acest sens semnale către unitatea aritmetică şi logică;
c) prelucrarea poate să necesite un apel la unităţile de intrare / ieşire
sau la memoria centrală.
Schema generală a unui sistem de calcul este prezentată în continuare.

unitatea centrală
de prelucrare
instrucţiuni
unitatea de control memoria centrală
şi de comandă

date
unitatea de calcul

unităţi de intrare/ieşire

controler de
periferice

unităţi periferice

Memoria centrală conţine în principal două tipuri de informaţii:


instrucţiunile diferitelor programe şi datele necesare execuţiei acestora.
Instrucţiunile sunt memorate sub formă de cod binar. Se remarcă faptul că
la nivel fizic memoria centrală nu conţine decât biţi, care constituie unitatea
elementară de informaţie. Un bit poate lua fie valoarea 1, fie valoarea 0.

9
Biţii se regrupează câte 6, 7 sau 8 pentru a forma un caracter. Un caracter
constituit dintr-o succesiune de 8 biţi se numeşte octet byte.
În paralel cu caracterele, care constituie o unitate logică de informaţie,
memoria centrală a sistemului de calcul este divizată fizic în locaţii, iar
fiecărei locaţii îi corespunde un cuvânt de memorie care posedă o adresă
proprie. Lungimea unui cuvânt de memorie variază de la un sistem de calcul
la altul, dar valorile 32 şi 64 tind să se generalizeze în majoritatea sistemelor
de calcul. Lungimea unui cuvânt de memorie este o caracteristică
importantă a arhitecturii unui sistem de calcul şi reflectă structura
componentelor sale funcţionale (în special unitatea centrală).
Un cuvânt de memorie word este unitatea adresabilă de informaţie,
adică orice operaţie de citire sau de scriere se realizează asupra unui cuvânt.
Fiecărui cuvânt de memorie îi sunt deci asociate: o adresă (unică),
indicând poziţia sa în memorie şi un conţinut (instrucţiune sau dată).
Capacitatea unei memorii se poate exprima în funcţie de numărul de
cuvinte de memorie ca şi de numărul de biţi dintr-un cuvânt.
Un registru este o locaţie de memorie având o funcţie particulară. În
memoria centrală se găsesc două tipuri de registre: registru de adresă, care
conţine adresa unui cuvânt de memorie şi registru cuvânt, care păstrează
conţinutul unui cuvânt de memorie.
Un registru cuvânt are aceeaşi mărime cu un cuvânt de memorie, în timp
ce un registru de adresă trebuie să permită adresarea tuturor cuvintelor.
Operaţiile posibile în memoria centrală sunt citirea şi scrierea unui
cuvânt de memorie:
a) citirea: registrul de adresă conţine adresa cuvântului de citit, iar o
copie a conţinutului este transferată în registrul cuvânt;
b) scrierea: registrul de adresă conţine adresa unui cuvânt în care se va
scrie conţinutul registrului cuvânt.
Timpul necesar scrierii sau citirii unui cuvânt de memorie se numeşte
timp de acces (de ordinul nanosecundelor şi microsecundelor).
Dacă timpul de acces este identic pentru fiecare cuvânt al memoriei
centrale, atunci avem de-a face cu o memorie RAM Random Access
Memory, adică o memorie cu acces aleator sau acces direct.
Unitatea centrală de prelucrare (CPU) este constituită din unitatea de
comandă şi unitatea de calcul.
Unitatea de comandă asigură controlul execuţiei instrucţiunilor unui
program şi conţine două registre importante:
a) registru de instrucţiuni (RI) care conţine adresa instrucţiunii în
curs de execuţie (o instrucţiune comportă mai multe câmpuri: un
câmp cod – operaţie şi între 0 şi 3 câmpuri operand);

10
b) registru contor ordinal (CO) care conţine adresa următoarei
instrucţiuni de executat. În general, instrucţiunile se succed
secvenţial iar CO se incrementează cu o unitate la fiecare ciclu
CPU, pentru a obţine adresa instrucţiunii următoare. În anumite
situaţii (de exemplu pentru instrucţiunile de salt) este necesară
forţarea valorii contorului ordinal.
Unitatea de comandă conţine de asemenea un dispozitiv de decodificare
a instrucţiunilor (decodificator) şi un dispozitiv de control al secvenţei de
comenzi care activează circuitele necesare execuţiei instrucţiunii curente.
Înlănţuirea comenzilor se realizează prin intermediul unui ceas sistem.
Unitatea de calcul sau aritmetică şi logică (UAL) conţine toate
circuitele electronice care realizează efectiv operaţiile dorite. Operanzii
acestor operaţii se găsesc în registrele unităţii.
Registrele UAL se divizează în diverse categorii:
a) registre aritmetice: servesc efectuării operaţiilor aritmetice;
b) registre de bază şi index: permit calculul de adresă în raport cu o
valoare de bază sau un index;
c) registre generale: realizează diverse operaţii cum ar fi stocarea
rezultatelor intermediare;
d) registrul de stare PSW: Program Status Word: indică starea
sistemului la un moment dat.
Unităţile de intrare / ieşire (I / O) sunt elemente care premit transferul
informaţiilor între unitatea centrală şi unităţile periferice. Unităţile de intrare
/ ieşire cele mai cunoscute sunt: unităţile de tip bus, cele care asigură acces
direct la memorie DMA: Direct Memory Access şi unităţile de canal.
Unităţile periferice se repartizează în două clase:
a) unităţi de transfer care permit sistemului de calcul să realizeze
schimburi de date cu exteriorul (ecran, tastatură, imprimantă etc.);
b) memoriile auxiliare (discuri, benzi, cartuşe magnetice etc.) care
permit stocarea permanentă a unui volum mare de informaţii la un
preţ scăzut; ele se utilizează datorită faptului că memoria centrală
este volatilă şi informaţiile se şterg când se opreşte sistemul, pe când
suporturile magnetice sunt memorii permanente.
În concluzia acestui capitol vom prezenta două aspecte simple care
exprimă faptul că un sistem de calcul este o maşină care execută la nivelul
său de bază decât operaţii elementare:
a) Toate sistemele de calcul se compun în principal din milioane sau
chiar miliarde de tranzistoare care nu pot efectua decât operaţii
elementare foarte rapid;

11
b) Un sistem de calcul este o maşină care trebuie programată corect,
adică trebuie prevăzut şi explicat absolut tot ceea ce el trebuie să
realizeze repede şi bine.
2 MODELE DE DATE ÎN SISTEMELE DE CALCUL

2.1 Reprezentarea informaţiei


Informaţiile prelucrate prin sistemele de calcul sunt de diverse tipuri dar ele
sunt reprezentate la nivel elementar sub formă binară. O informaţie elementară
corespunde deci unei cifre binare (0 sau 1) numită bit. O informaţie mai
complexă (un caracter, un număr etc.) se exprimă printr-o mulţime de biţi.
Codificarea unei informaţii constă în a stabili o corespondenţă între
reprezentarea externă a informaţiei (caracterul A sau numărul 33, de
exemplu) şi reprezentarea sa internă, care este o secvenţă de biţi.
Avantajele reprezentării binare se referă în special la facilitatea de
realizare tehnică cu ajutorul elementelor bistabile (sisteme cu 2 stări de
echilibru) precum şi la simplitatea efectuării operaţiilor fundamentale sub
forma unor circuite logice, utilizând logica simbolică cu două stări (0, 1).
Informaţiile prelucrate în sistemele de calcul sunt de două tipuri:
instrucţiuni şi date.
Instrucţiunile, scrise în limbaj maşină, reprezintă operaţiile efectuate în
sistemul de calcul şi ele sunt compuse din mai multe câmpuri:
 codul operaţiei de efectuat;
 operanzii implicaţi în operaţie.
Codul operaţiei trebuie să suporte o operaţie de decodificare
(transformare inversă codificării) pentru a se putea efectiv executa.
Datele sunt operanzii asupra cărora acţionează operaţiile (prelucrările),
sau sunt produse de către acestea. O adunare, de exemplu, se aplică la doi
operanzi, furnizând un rezultat care este suma acestora.
Se pot distinge datele numerice, rezultat al unei operaţii aritmetice, sau
date nenumerice, de exemplu simbolurile care constituie un text.

Date nenumerice
Datele nenumerice corespund caracterelor alfanumerice: A, B, ..., Z, a,
b, ..., z, 0, 1, 2, ..., 9 şi caracterelor speciale: ?, !, “, $, ;, ...
Codificarea se realizează pe baza unei tabele de corespondenţă specifică
fiecărui cod utilizat. Printre cele mai cunoscute coduri putem enumera:
 BCD Binary Coded Decimal prin care un caracter este codificat pe 6 biţi;
 ASCII American Standard Code for Information Interchange(7 biţi);
 EBCDIC Extended Binary Coded Decimal Internal Code (8 biţi).
Figura următoare prezintă corespondenţa dintre diferite coduri.

12
caracter BCD ASCII EBCDIC
0 000000 0110000 11110000
1 000001 0110001 11110001
2 000010 0110010 11110010
... ... ... ...
9 001001 0111001 11111001
A 010001 1000001 11000001
B 010010 1000010 11000010
C 010011 1000011 11000011
(6 biţi) (7 biţi) (8 biţi)

Figura 2.1 Tabela de corespondenţă între coduri

Datele numerice
Datele numerice sunt de următoarele tipuri:
a) numere întregi pozitive sau nule: 0; 1; 315...
b) numere intregi negative: -1; -155...
c) numere fracţionare: 3.1415; -0.5...
d) numere în notaţie ştiinţifică: 4.9  107 ; 1023 ...
Codificarea se realizează cu ajutorul unui algoritm de conversie asociat
tipului de dată corespunzător. Operaţiile aritmetice (adunare, scădere,
înmulţire, împărţire) care se pot aplica asupra acestor date se efectuează de
regulă în aritmetica binară. Figura de mai jos arată regulile operaţiilor binare.

0+0=0 00=0
0+1=1 01=0
1+0=1 10=0
1 + 1 = 10 11=1

Numerele întregi pozitive sau nule cuprind: 0, 1, 2, ...,N, N + 1...

Sisteme de numeraţie
Un sistem de numeraţie face să-i corespundă unui număr N, un anumit
simbolism scris şi oral. Într-un sistem de numeraţie cu baza p > 1, numerele
0, 1, 2, ..., p –1 sunt numite cifre.
Orice număr întreg pozitiv poate fi reprezentat astfel:
N = anpn + an-1pn-1 + ... + a1p + a0
cu ai 0, 1, 2, p-1 şi an  0.

13
Se utilizează de asemenea notaţia echivalentă N = anan-1...a1a0.
Numerele scrise în binar sunt adesea compuse dintr-un mare număr de biţi,
şi de aceea se preferă exprimarea acestora în sistemele octal (p = 8) sau
hexazecimal (p = 16), deoarece conversia cu sistemul binar este foarte simplă.

Schimbări de bază
a) binar  zecimal
Conversia se realizează prin însumarea puterilor lui 2 corespunzătoare
biţilor egali cu 1;
Exemplu: 101012= 24 + 22 + 20 = 16 + 4 + 1 = 2110
b) zecimal  binar
Conversia se efectuează prin împărţiri întregi succesive cu 2. Testul de
oprire corespunde situaţiei câtului nul. Numărul binar este obţinut
considerând resturile în ordinea inversă.
Exemplu: Conversia lui 26:
26 : 2 = 13 rest 0
13 : 2 = 6 rest 1
6:2=3 rest 0
3:2=1 rest 1
1:2=0 rest 1
Se obţine (de jos în sus): 2610 = 110102.
c) octal (hexazecimal)  zecimal
Conversia se reduce la însumarea puterilor lui 8 (16).
d) zecimal  octal (hexazecimal)
Conversia se efectuează prin împărţiri întregi succesive prin 8 (16). Testul
de oprire corespunde situaţiei câtului nul. Numărul octal (hexazecimal) este
obţinut considerând resturile obţinute de la ultimul către primul.
e) octal (hexazecimal)  binar
Conversia corespunde dezvoltării fiecărei cifre octale (hexazecimale) în
echivalentul ei binar pe 3 (4) biţi.
Exemplu: 278 = 010’1112 deoarece 28 = 0102 şi 78 = 1112.
3A16 = 0011’10102 deoarece 316= 00112 şi A16=10102.
f) binar  octal (hexazecimal)
Conversia se realizează înlocuind de la dreapta la stânga, grupele de 3 (4)
biţi prin cifra octală (hexazecimală) corespunzătoare. Dacă numărul de biţi nu
este multiplu de 3 (4) se completează configuraţia binară la stânga cu zerouri.
Exemplu: 1010112= 538 = 2B16 .

Numere întregi negative


Numerele întregi negative pot fi codificate prin trei metode:

14
 semn şi valoare absolută (SVA);
 complement logic sau restrâns sau faţă de 1 (C1);
 complement aritmetic sau adevărat sau faţă de 2 (C2);
Prin metoda „semn şi valoare absolută“, numerele se codifică sub
forma:  valoare absolută.
Prin această reprezentare se sacrifică un bit pentru semn. În mod normal,
0 este codul semnului „+”, iar 1 este codul semnului „-”. În aceste condiţii,
pe un cuvânt de k biţi se pot reprezenta numere întregi pozitive şi negative
N, astfel încât: - (2k-1- 1)  N  (2k-1- 1).
Această metodă de reprezentare prezintă unele inconveniente:
 numărul zero are două reprezentări distincte: 000...0 şi 100...0, adică
+0 şi -0;
 tabelele de adunare şi înmulţire sunt complicate din cauza bitului de
semn care trebuie tratat separat.

Complement logic şi aritmetic


Complementul logic (complement faţă de 1) se calculează înlocuind,
pentru valorile negative, fiecare bit 0 cu 1 şi 1 cu 0.
Complementul aritmetic (complement faţă de 2) este obţinut adunând o
unitate la valoarea complementului logic.
Exemplu: Reprezentarea numărului (-6) pe 4 biţi: +6 = 0110
Semn şi valoare absolută: - 6 = 1110
Complement faţă de 1: - 6 = 1001
Complement faţă de 2: - 6 = 1010
Se poate uşor constata că intervalul numerelor întregi N care se pot
reprezenta în complement faţă de 1 este acelaşi ca şi pentru reprezentarea
„semn şi valoare absolută”.
Pentru reprezentarea în complement faţă de 2 există o valoare în plus,
deci pentru k biţi vom avea: -2k-1  N  (2k-1-1).
Reprezentarea în complement faţă de 1 recunoaşte două zerouri (+0 şi –0),
dar este simetrică, deoarece aceleaşi numere pozitive şi negative sunt
reprezentabile, iar această situaţie se poate uşor realiza electronic.
În complement faţă de 1 sau faţă de 2, operaţiile aritmetice sunt
avantajoase, deoarece operaţia de scădere se realizează prin adunarea
complementului.
Într-o adunare în complement faţă de 1, o cifră de transport către ordinul
superior generată de bitul de semn trebuie adăugată la rezultatul obţinut, spre
deosebire de complementul faţă de 2, când această cifră de transport se ignoră.

15
În complement faţă de 1 sau 2 nu se produce depăşire de capacitate decât
în cazul în care cifrele de transport generate de bitul de semn şi de bitul
anterior acestuia sunt diferite.
Se poate remarca faptul că bitul cel mai din stânga (bitul de semn) este
întotdeauna 0 pentru numere pozitive şi 1 pentru cele negative şi aceasta
pentru fiecare din cele trei reprezentări, conform tabelului următor.

(16 biţi  216 = 65536 = 2  32768 valori posibile)


zecimal semn şi valoare complement complement
absolută faţă de 2 faţă de 1
+32767 0111...1...1111 0111...1...1111 0111...1...1111
+32766 0111...1...1110 0111...1...1110 0111...1...1110
... ... ... ...
+1 0000...0...0001 0000...0...0001 0000...0...0001
+0 0000...0...0000 0000...0...0000 0000...0...0000
-0 1000...0...0000 ------------------ 1111...1...1111
-1 1000...0...0001 1111...1...1111 1111...1...1111
... ... ... ...
-32766 1111...1...1110 1000...0...0010 1000...0...0001
-32767 1111...1...1111 1000...0...0001 1000...0...0000
-32768 ------------------ 1000...0...0000 ------------------

Numere fracţionare
Numerele fracţionare sunt numerele subunitare.

Schimbări de bază
a) binar  zecimal
Conversia se face adunând puterile (negative) corespunzătoare ale lui 2.
Exemplu: 0.012 = 0  2-1 + 1  2-2 = 0.2510.
b) zecimal  binar
Conversia se efectuează prin înmulţiri succesive cu 2 a numerelor pur
fracţionare. Acest algoritm trebuie să se termine când se obţine o parte
fracţionară nulă sau când numărul de biţi obţinuţi corespunde mărimii
registrului sau a cuvântului de memorie în care se va stoca valoarea.
Numărul binar se obţine citind părţile întregi în ordinea calculării lor.
Exemplu: 0.125  2 = 0.250 = 0 + 0.250
0.25  2 = 0.50 = 0 + 0.50
0.50  2 = 1.0 = 1 + 0.0
Vom considera părţile întregi de sus în jos, deci: 0.2510= 0.0012.

16
Pentru numerele fracţionare se pot remarca reprezentările în virgulă fixă
şi virgulă mobilă.

Virgula fixă (VF)


Sistemele de calcul nu posedă virgula la nivelul maşinii, deci
reprezentarea numerelor fracţionare se face ca şi când acestea ar fi întregi,
cu o virgulă virtuală a cărei poziţie este controlată de către programator.
Datorită dificultăţii de gestionare a virgulei de către programator (pot
apare frecvent situaţii de depăşire a capacităţii de memorare), se preferă
soluţia aritmeticii în virgulă mobilă.

Virgula mobilă (VM)


Primele sisteme de calcul utilizau doar virgula fixă pentru efectuarea
operaţiilor aritmetice, iar către sfârşitul anilor ‘50, în urma apariţiei logicii
cablate s-a introdus pe scară largă reprezentarea în virgulă mobilă a
numerelor fracţionare.
În majoritatea sistemelor de calcul actuale destinate în special aplicaţiilor
de natură tehnico-ştiinţifică, cele două metode de reprezentare (virgula fixă
şi virgula mobilă) coexistă şi sunt foarte utile.
Reprezentarea în virgulă mobilă constă în a reprezenta numerele sub
forma următoare:

N = M  BE cu: B = baza (2, 8, 10, 16...)


M = mantisa
E = exponentul

Exponentul este un număr întreg, mantisa normalizată este un număr pur


fracţionar (fără cifre semnificative la partea întreagă). Cu excepţia numărului
zero (în general reprezentat prin cuvântul 000...0), vom avea întotdeauna:
0.12   M  12 , sau 0.510   M  110.
Exponentul şi mantisa trebuie să poată reprezenta atât numere pozitive
cât şi negative. Cel mai adesea, mantisa admite o reprezentare sub forma
„semn şi valoare absolută”, iar exponentul este fără semn, dar decalat.
Exemplu:

SM ED M

17
unde SM este semnul mantisei, ED este exponentul decalat şi M mantisa.
Pentru nu număr de k biţi rezervaţi pentru ED se pot reprezenta fără
semn 2k valori, de la 0 la 2k – 1. Decalajul considerat este 2k-1, ceea ce
permite ca valorile de la 0 la 2k-1-1 pentru ED să corespundă unui exponent
real (ER) negativ, iar valorile de la 2k-1 la 2k – 1 ale lui ED să corespundă
unui exponent real (ER) pozitiv. Deci domeniul de valori reprezentabile
pentru exponentul real este de la –2k-1 la 2k-1-1.
De exemplu, pentru k = 4, pe cei 4 biţi putem reprezenta fără semn
numere de la 0 la 15 pentru ED. Decalajul considerat este 2 k-1 = 23 = 8, deci
pentru exponentul real (ER) putem considera valori de la - 2k-1 = -23 = -8 şi
până la 2 k-1 – 1 = 23 – 1 = 7.
Relaţia existentă se poate scrie astfel: ER = ED – D.
Exponentul determină intervalul de numere reprezentabile în sistemul de calcul,
iar numerele prea mari pentru a putea fi reprezentate corespund unei „depăşiri
superioare” de capacitate de memorare overflow, iar numerele prea mici
corespund unei „depăşiri inferioare” de capacitate de memorare underflow.
Mărimea mantisei exprimă precizia de reprezentare a numerelor.
Avantajul utilizării virgulei mobile faţă de virgula fixă constă în
intervalul mult mai extins al valorilor posibile de reprezentat.

Standardul IEEE 754


Standardul IEEE Institute of Electrical and Electronics Engineers
defineşte următoarele formate de reprezentare a numerelor în virgulă mobilă:
a) simplă precizie pe 32 de biţi (1 bit pentru SM, 8 biţi pentru ED şi
23 pentru M);
b) dublă precizie pe 64 biţi (1 bit pentru SM, 11 biţi pentru ED şi 52
biţi pentru M);
c) dublă precizie extinsă pe 96 biţi (1 bit pentru SM, 15 biţi pentru
ED şi 80 biţi pentru M) .
d) precizie cvadruplă pe 128 biţi (1 bit pentru SM, 15 biţi pentru ED
şi 112 biţi pentru M)
Exponentul este decalat cu 128 pentru reprezentarea în simplă precizie şi
cu 1024 pentru reprezentarea în dublă precizie. Mantisa fiind normalizată,
există siguranţa că primul bit al mantisei are valoarea 1, ceea ce permite
omiterea sa (bit ascuns) pentru creşterea preciziei de reprezentare, dar
complică prelucrarea informaţiei.
Figura următoare prezintă schematic tipurile diverse de informaţii
prelucrate în sistemele de calcul.

18
INFORMAŢII

INSTRUCŢIUNI DATE
(diferite formate în cod maşină)

Cod oper. Operanzi

Numerice Nenumerice
Codificare prin tabele
BCD (6 biţi)
ASCII (7 biţi)
EBCDIC (8 biţi)

Numere întregi pozitive Numere întregi negative


(conversie directă
zecimal  binar)
SVA C1 C2

Numere fracţionare

VF VM (mantisă, bază, exponent)

Coduri zecimale codificate în binar


Dacă aritmetica sistemelor de calcul este de regulă binară, ea poate fi de
asemenea şi zecimală. În cazul calculatoarelor de buzunar şi de birou, în
sistemele de calcul specifice aplicaţiilor comerciale, operaţiile se efectuează
direct asupra reprezentării zecimale a numerelor.
Un număr zecimal, care cuprinde una sau mai multe cifre (de la 0 la 9),
este codificat cu ajutorul biţilor utilizând anumite coduri. Tabela de mai jos
prezintă patru exemple de astfel de coduri.
19
Exemplu: zecimal : 129
binar : 10000001 = 27 +20 = 128 + 1
BCD : 0001’0010’1001

zecimal BCD excedent-3 2 din 5 bicvintal


0 0000 0011 00011 01 00001
1 0001 0100 00101 01 00010
2 0010 0101 00110 01 00100
3 0011 0110 01001 01 01000
4 0100 0111 01010 01 10000
5 0101 1000 01100 10 00001
6 0110 1001 10001 10 00010
7 0111 1010 10010 10 00100
8 1000 1011 10100 10 01000
9 1001 1100 11000 10 10000

Codul BCD
Codul BCD Binary Coded Decimal este unul dintre cele mai răspândite
coduri cu semnificaţia „zecimal codificat în binar”, în care fiecare cifră zecimală
este codificată în mod individual în echivalentul său binar pe patru biţi.
Orice cifră zecimală se poate reprezenta pe patru biţi, dar valorile
reprezentabile pe patru biţi sunt în număr de 24 = 16, deci vor rămâne 6
configuraţii neutilizate, de care trebuie să se ţină seama la efectuarea
operaţiilor aritmetice.
În situaţia operaţiei de adunare trebuie să se adauge 6, ori de câte ori
rezultatul este superior lui 9, iar pentru operaţia de scădere se va extrage 6
dacă rezultatul este negativ.
Exemplu: zecimal binar BCD
15+ 01111+ 0001’0101+
18 10010 0001’1000
--- ------- -------------
33 100001 0010’1101 > 9
(= 33) 0110 +6
-------------
0011’0011 (=33)
Operaţiile aritmetice sunt deci destul de complicate, dar operaţiile de
intrare / ieşire sunt uşor de realizat deoarece fiecare entitate BCD este direct
asociată unui caracter. Din aceste motive, codul BCD se găseşte în sistemele
de calcul de gestiune, unde operaţiile aritmetice sunt mult mai puţin
numeroase decât operaţiile de intrare / ieşire.

20
Codul BCD este un cod ponderat 8 – 4 – 2 – 1, cei patru biţi necesari
pentru a codifica o cifră au o pondere corespunzătoare cu poziţia lor,
respectiv 8 = 23 pentru bitul cu numărul 3, 4 = 22 pentru bitul cu numărul 2,
2 = 21 pentru bitul cu numărul 1 şi 1 = 20 pentru bitul cu numărul 0.

Codul „excedent – 3”
Codul „excedent - 3” nu este un cod ponderat, fiecare cifră zecimală este
codificată separat în echivalentul său binar + 3.
Exemplu: 12910 = 0100’0101’1100 excedent - 3
Avantajul acestui cod faţă de codul BCD este acela că operaţiile
aritmetice sunt mai simple.
De exemplu, complementarea faţă de 9 (similară în sistemul zecimal cu
complementarea faţă de 1 în sistemul binar) este imediată: este suficientă
complementarea fiecărui bit.

Codul „2 din 5”
Codul „2 din 5” este un cod neponderat în care fiecare cifră zecimală
este codificată pe 5 biţi, dintre care numai 2 au valoarea 1.
Exemplu: 12910 = 00101’00110’11000 cod „2 din 5”
Avantajul acestui cod este acela de detectare (nu şi corectare) a unei erori
sau a unui număr impar de erori.

Codul bicvintal
Codul bicvintal este un cod ponderat 50’43210 care permite detectarea
erorilor. O cifră zecimală este codificată printr-un număr binar pe 7 biţi,
având un singur bit egal cu 1 pe primele 2 poziţii din stânga şi un singur bit
egal cu 1 pe 5 poziţii cele mai din dreapta.
Exemplu: 12910 = 0100010’0100100’1010000 bicvintal.

2.2 Coduri de erori

2.2.1 Problema transmiterii informaţiei


Problema transmiterii informaţiei prin diferite canale este mereu întâlnită
în viaţa cotidiană sub diverse forme: vorbirea umană, convorbirea telefonică,
transmiterea prin radio, comunicaţiile spaţiale, dialogul om-calculator etc.
Mesajele unei surse trebuie transmise la o anumită destinaţie printr-un
canal de transmisie.
O schemă simplă a unui sistem de transmitere a informaţiei este
prezentată în figura următoare:

21
Sursa → Codificator → Canal → Decodificator → Destinaţie

Prin canal se înţelege o combinaţie între mediul de transmisie şi


echipamentul capabil de a primi semnalele de la sursă şi de a furniza
semnalele la destinaţie.
În practică întâlnim două tipuri de canale: cu zgomot şi fără zgomot.
În primul caz, la transmiterea unor semnale, acestea sunt recepţionate la
destinaţie nealterate. În al doilea caz, este posibil ca anumite semnale să fie
alterate prin trecerea prin canal.
Una dintre problemele importante în transmitere este verificarea
corectitudinii transmiterii informaţiei. Dacă, spre exemplu, un cuvânt de cod
se reprezintă pe n biţi, se pot crea maxim 2n cuvinte de cod. Un astfel de cod
nu poate detecta erorile introduse pe canal.
Principiul general al detecţiei erorilor este următorul.
Pe lângă biţii care reprezintă informaţia propriu-zisă, în cod se mai
adaugă o serie de biţi de control. Aceştia sunt construiţi de către
codificatorul care urmează sursei, plecând evident de la biţii de informaţie.
Deci pe canal pleacă atât informaţia propriu-zisă, cât şi biţii de control.
La recepţie, decodificatorul controlează corectitudinea valorilor biţilor de
control. Faptul că aceşti biţi nu au valorile pe care ar trebui să le aibă plecând de
la biţii de informaţie, dă certitudinea că de-a lungul canalului au apărut zgomote
care au denaturat informaţia. Un astfel de cod îl vom numi cod detector de erori.
În cazul în care biţii de control au valori corecte, atunci, cu mare probabilitate,
transmiterea s-a făcut corect. Este însă posibil ca transmiterea să se efectueze
eronat şi totuşi, biţii de control să aibă valori corecte.
Unele sisteme de codificare sunt capabile să şi corecteze, într-o măsură
oarecare, erorile de transmitere. Acestea spunem că sunt coduri detectoare
de erori.
Un sistem de codificare este cu atât mai bun cu cât probabilitatea de a declara
că este corect un mesaj care este de fapt eronat este mai mică. Din păcate,
sisteme de codificare perfecte nu există!

2.2.2 Coduri liniare binare

2.2.2.1 Control prin bit de paritate


Cel mai simplu mod de detectare a erorilor de transmitere este utilizarea
bitului de paritate. Să considerăm un mesaj format din m biţi:
s1, s2, ..., sm
Acestui mesaj îi mai adăugăm încă un bit p care se va completa astfel
încât numărul total de biţi 1 din configuraţia:
s1, s2, ..., sm, p
22
să fie un număr par. După determinarea (automată) a lui p, pe canal se vor transmite
aceşti m+1 biţi.
La recepţie, se verifică dacă numărul total de biţi 1 din mesaj este un
număr par. Dacă nu, atunci cu siguranţă pe canal au intervenit erori.
Cel mai simplu mod de determinare şi control al bitului de paritate este
suma modulo 2: (0+0=1+1=0; 0+1=1+0=1).
Este însă evident că existenţa unui număr par de biţi 1 nu asigură
corectitudinea transmiterii mesajului. Este suficient, de exemplu, să se
inverseze între ei un bit 0 cu un bit 1 ca mesajul să nu mai fie corect, însă
bitul de paritate nu va sesiza această inversare.
Trebuie de asemenea remarcat că prin această metodă nu se poate identifica
poziţia binară unde a avut loc eroarea. În secţiunea următoare vom descrie un cod
care face această identificare.
Cele prezentate mai sus sunt cunoscute sub numele de convenţia pară a
controlului de paritate. Convenţia impară este aceea în care bitul p este ales
astfel încât numărul total de biţi 1 să fie impar.
Controlul de paritate este mult utilizat. De exemplu, în memoria internă,
fiecărui octet îi sunt asociaţi 9 biţi: 8 biţi de informaţie şi un bit de paritate. La
înregistrarea octetului, se completează şi bitul de paritate. La fiecare citire a
octetului se controlează corectitudinea bitului de paritate. În caz de neparitate se
semnalează o eroare.
O generalizare firească este controlul de paritate încrucişat (cod iterativ).
Mesajul este imaginat ca o matrice de biţi, completându-se o coloană de
paritate şi o linie de paritate. În acest caz, se poate detecta bitul eronat: el se va
afla la intersecţia liniei şi coloanei care nu verifică biţii de paritate.

Definirea codului liniar binar


În cele ce urmează, toate operaţiile aritmetice vor fi cele din inelul boolean
(B2, +, .). Se ştie că în acest inel se pot defini matrice şi operaţii cu aceste matrice.
Fie Gm,n o matrice cu m linii şi n coloane. Presupunem n > m; notăm prin
k întregul ce verifică n = m+k. Elementele ai,j ale matricei Gm,n aparţin
mulţimii B2. De asemenea, în G nu există două coloane egale şi în fiecare
coloană există cel puţin un element cu valoarea 1. O astfel de matrice o vom
numi matrice generatoare.

1 0 . . . 0 a11 . . . a1k 
 
0 1 . . . 0 a21 . . . a2 k 
Gm, n  . ..
 
0 0 amk 
 . . . 1 am1 . . .

23
Definiţia 2.1
O aplicaţie C: B2m → B2n este un cod liniar binar de dimensiuni (n, m)
generat de o matrice G, dacă pentru orice secvenţă (s1, s2, ..., sm) din B2m,
codul acesteia se obţine astfel:
C((s1, s2, ..., sm))=(s1, s2, ..., sm) ∙ Gm,n
Din definirea înmulţirii matricelor şi din modul în care s-a definit
matricea generatoare G, rezultă că C((s1, s2, ..., sm)) este o secvenţă (vector)
din B2n .
După efectuarea înmulţirii, se obţine:
C((s1, s2, ..., sm)) = (s1, s2, ..., sm, c1, c2, ..., ck),
unde
m
cj  s a
i 1
i ij , j  1, k

Primii m biţi ai cuvântului de cod sunt biţii de informaţie, iar următorii k


biţi sunt biţii de control. Fiecare dintre aceştia din urmă se obţine ca produs
scalar dintre vectorul biţilor de informaţii şi una din ultimele k coloane ale
matricei generatoare G.
Să considerăm de exemplu, codul (7, 4) generat de matricea:
1 0 0 0 0 1 1
 
0 1 0 0 1 0 1
G4,7  
0 0 1 0 1 1 0
 
0 0 0 1 1 1 1
 
Fie (s1, s2, s3, s4) din B24 un mesaj de transmis. Codificarea lui este:
C((s1, s2, s3, s4)) = (s1, s2, s3, s4, s2+s3+s4, s1+s3+s4, s1+s2+s4),
Toate operaţiile fiind cele din B2. De exemplu,
C((0, 1, 1, 0)) = (0, 1, 1, 0, 1+1+0, 0+1+0, 0+1+0) = (0, 1, 1, 0, 0, 1, 1).
Codificarea folosind bitul de paritate este un caz particular de cod liniar
binar. Matricea generatoare este dată mai jos.
 1 0    0 1
 
 0 1    0 1
Gm,m 1   
 
 0 0    1 1
 

Relaţii de control în coduri liniare binare

24
Plecând de la matricea generatoare Gm,n, se construieşte matricea de
control a codului Hk,n, având k linii şi n coloane:
 a11 a21    am1 1 0    0 
 
 a12 a22    am 2 0 1    0 
H k ,n   
 
a       
 1k a 2 k a mk 0 0 1 
Pentru codul (7, 4) definit mai sus, avem:
0 1 1 1 1 0 0
 
H 3, 7   1 0 1 1 0 1 0 
1 1 0 1 0 0 1
 
Să notăm Am,k, Atk,m, In şi Om,n matricele de mai jos:
 a11 a12    a1k 
 
 a21 a22    a2k 
Am, k  
      
 
a 
 m1 am 2    amk 
 a11 a21   
am1 
 
a a22   
am 2 
Akt , m   12
      
 
a    amk 
 1k a2 k

1 0    0 0 0    0
   
0 1    0 0 0    0
In    Om,n  
           
   
0 0    1 0 0    0 
  
În continuare, vom adopta scrierea „pe blocuri” a matricelor G şi H,
plecând de la matricele A şi I.
Gm,n = [Im| Am,k], Hk,n = [Atk,m | k].
Este uşor de văzut că transpusele acestora sunt:
 I   Am, k 
Gnt , m   tm  GH nt , k   
 Ak , m   Ik 

Teorema 2.1
Au loc următoarele egalităţi:

25
Gm,n ∙ Htn,k = Om,k şi Hk,n ∙ Gtn,m = Ok,m
Înainte de a trece la demonstraţie, trebuie spus că în teoria codurilor,
aceste egalităţi sunt cunoscute sub numele de condiţii de ortogonalitate.
Pentru demonstraţie, este suficient să efectuăm înmulţirea „pe blocuri” a
matricelor. Dimensiunile matricelor ne permit acest mod de a opera.
Verificăm prima egalitate:
A 
Gm,n ∙ Htn,k = [Im| Am,k] ∙  m, k  = Im ∙ Am,k + Am,k ∙ Ik = Am,k + Am,k = Om,k
 Ik 
Verificăm şi a doua egalitate:
 I 
Hk,n ∙ Gtn,m = [Atk,m|Ik] ∙  tm  = Atk,m ∙ Ik + Ik∙ Atk,m= Atk,m + Atk,m = Ok,m
 Ak , m 
Acest rezultat, împreună cu definiţia funcţiei de codificare liniară binară,
conduce la următorul rezultat:

Teorema 2.2
Pentru orice sursă s1, s2, ..., sm, are loc:
Hk,n ∙[C((s1, s2, ..., sm))] t = Ok,1
Demonstraţie:
Hk,n ∙ [C((s1, s2, ..., sm))] t = Hk,n ∙ [(s1, s2, ..., sm) ∙ Gm,n] t = Hk,n ∙ G tm,n ∙
(s1, s2, ..., sm) t = Ok,1
Din această teoremă rezultă criteriul de verificare a corectitudinii
transmisiei. Presupunem că de la sursă se emite C((s1, s2, ..., sm)), adică biţii:
(s1, s2, ..., sm, c1, c2, ..., ck),
şi se recepţionează biţii:
(s'1, s'2, ..., s'm, c'1, c'2, ..., c'k).
Să notăm Hk,n ∙ (s'1, s'2, ..., s'm, c'1, c'2, ..., c'k)t = (z1, z2, ..., zk)t. Acest
vector va fi numit vector de control sau sindrom.
Dacă vectorul de control al parităţii este vectorul nul, adică (z1, z2, ..., zk)t
= Ok,1 atunci la destinaţie s-a recepţionat un cod corect şi mesajul este
acceptat. În caz contrar, s-a detectat o eroare survenită în timpul transmisiei
şi mesajul nu este acceptat.

2.2.2 Evaluarea capacităţii de detecţie în coduri liniare binare

Definiţia 2.2
Capacitatea de detecţie a unui cod este dată de următorul raport:
Numar de cuvinte eronate detectabile prin cod
C
Numar total de cuvinte eronate

26
Acest raport are o valoare subunitară şi este cu atât mai bun cu cât
valoarea lui este mai apropiată de 1.
Să determinăm capacitatea de detecţie a unui cod liniar binar (n, m).
Mulţimea B2n are 2n elemente, iar mulţimea B2m are 2m elemente. Deci sursa
poate emite maximum 2m cuvinte de cod, cuvinte codificate cu vectori din
B2n. Astfel, un astfel de cod poate să detecteze ca eronate 2 n-2m elemente.
Numărul maxim de cuvinte eronate este evident 2n-1, adică toate cuvintele
posibile, cu excepţia celui care s-a transmis.
Capacitatea de detecţie a unui cod liniar binar este:
2n  2m 2m  k  2m
C 
2n  1 2m  k  1
Să delimităm această valoare a lui C. Mai întâi, avem:
2n  2m 2m  k  1
C n  m k 1
2 1 2 1
Apoi,
2m  k  2m 2m  k  2m 2m 1
C  m k  m k
 1  m k
 1 k
2 1 2 2 2
În consecinţă,
1
1 k  C  1
2
Această dublă delimitare a lui C este cu atât mai bună cu cât valoarea lui
k este mai mare, adică un cod liniar binar este cu atât mai bun cu cât sunt
mai mulţi biţi de control.
Acest număr de biţi nu poate fi oricât de mare. În definiţia matricei
generatoare G se precizează că ea trebuie să aibă coloane diferite, deci cu
siguranţă nu pot fi folosiţi mai mult de 2m biţi de control. Această delimitare
este exagerat de mare. Existenţa a prea mulţi biţi de control face ca mesajele
să fie exagerat de lungi, ceea ce face codul greu de manevrat.

Coduri iterative
În practică, pentru a se asigura o capacitate de detecţie mai mare, ca şi
pentru a avea siguranţa că este receptat cuvântul de cod emis de sursă, sunt
folosite codurile iterative (coduri încrucişate). Cel mai simplu cod de acest
fel presupune aplicarea bitului de paritate într-o matrice.
În acest scop, biţii mesajului sunt plasaţi într-o matrice, să zicem cu q
linii şi p coloane. Fie bij biţii mesajului. Pentru a se asigura controlul de
paritate încrucişat, se mai adaugă încă o linie şi o coloană la această matrice.
Matricea iniţială, la care s-au făcut aceste completări este:

27
 b11 b11    b1 p | l1 
b b12    b2 p | l2 
 21
       | 
 
 bq1 bq1    bqp | lq 
       | 
 
 t1 t2    tp | r 
Biţii t1, t2, ..., tp se numesc biţi de paritate transversală şi sunt astfel
aleşi, încât să fie asigurată paritatea fiecărei coloane. Ei verifică, pentru
fiecare j între 1 şi p (operaţiile sunt efectuate modulo 2):
q q
t j   bij  0, deci t j   bij , pentru j  1, p
i 1 i 1
Biţii l1, l2, ..., lq se numesc biţi de paritate longitudinală şi sunt astfel aleşi, încât
să fie asigurată paritatea fiecărei linii. Ei verifică, pentru fiecare j între 1 şi p:
p p
li   bij  0, deci li   bij , pentru i  1, q
j 1 j 1
Se pune în mod firesc întrebarea: bitul r, aflat în linia q+1 şi coloana p+1 a
matricei extinse satisface condiţia de paritate atât pentru linia q+1 cât şi pentru
coloana p+1? Răspunsul este afirmativ şi este dat de următoarea teoremă:

Teorema 2.3
Bitul r din codul iterativ, este bit de paritate atât pentru coloana de paritate
longitudinală l1, l2, ..., lq, cât şi pentru linia de paritate transversală t1, t2, ..., tp.
Demonstraţia este imediată şi are la bază proprietatea de comutativitate a
operatorului de sumare:
p p q q p q
r   t j   b ij   b ij   l i
j1 j1 i 1 i 1 j1 i 1
Deci bitul r este stabilit în mod unic.
De exemplu, pentru q = 3 şi p = 7, o matrice extinsă cu biţii de paritate
încrucişată este:
1 0 0 1 0 1 0 1 |
0 1 0 0 1 1 1 | 0 

0 1 1 0 1 1 0 | 0
 
        
 1 0 1 1 0 1 1 | 1 

28
2.2.3 Structura unui bloc de informaţie pe suport magnetic
Tehnologia de înregistrare a informaţiilor pe suport magnetic (disc
magnetic şi optic, dischetă, bandă streamer etc.) prevede adăugarea
combinată a mai multor tehnici de a detecta şi eventual de a corecta erori.
Un bloc de informaţie pe un suport magnetic conţine o structură
complexă de control. Biţii de informaţie sij sunt dispuşi într-o matrice, care
este completată cu încă o linie şi k+1 coloane, astfel:
s11    s1m | c11    c1k | l1 
      |      |  

s q1    s qm | c q1    c qk | l q 
 
      |      |  
 t 1    t m | u1    u k | r 
Fiecare linie i dintre cele q ale matricei de informaţii se completează cu k
biţi de control, furnizaţi de către un cod liniar binar (m+k, m) care are
matricea generatoare Gm,m+k şi matricea de control Hk,m+k. În acest cod,
elementele si1, si2, ..., sim constituie partea de informaţii, iar elementele ci1,
ci2, ..., cik constituie partea de control a codului respectiv.
Ultima coloană a liniei i, cu elementele notate li, conţine biţii de paritate
longitudinală, astfel încât linia:
si1, si2, ..., sim, ci1, ci2, ..., cik, li
să aibă un număr par de cifre 1.
Cea de-a q+1 linie conţine biţii de paritate transversală. Astfel, fiecare
coloană j dintre primele m:
s1j, ..., s2j, ..., sqj, tj
conţine un număr par de cifre 1. De asemenea, fiecare din următoarele k coloane:
c1j, ..., c2j, ..., cqj, uj
conţine un număr par de cifre 1.
Deci ultima linie şi cu ultima coloană sunt completate astfel, încât să
formeze un cod iterativ. Prin teorema 3 am demonstrat că alegerea
elementului r de pe poziţia (q+1, m+k+1) verifică atât paritatea longitudinală
a liniei cât şi pe cea verticală a coloanei lui.

Teorema 2.4
Din următoarele patru ipoteze:
1. Hk,m+k este matricea de control a unui cod liniar binar;
2. pentru fiecare j de la 1 la q configuraţia de m+k biţi: si1, si2, ..., sim, ci1, ci2,
..., cik este cuvânt de cod, cu m biţi de informaţie şi k biţi de control;
3. biţii t1, ..., tm asigură parităţile transversale ale coloanelor biţilor de
informaţie sij;

29
4.biţii u1, ..., uk asigură parităţile transversale ale coloanelor biţilor de
informaţie cij;
Atunci, configuraţia t1, ..., tm, u1, ..., uk este un cuvânt de cod liniar binar
generat de matricea Gm+k,m şi acceptat de matricea de control Hk,m+k, cu biţii notaţi
tj reprezentând partea de informaţie, iar biţii notaţi uj partea de control.

Demonstraţie: Este suficient să arătăm că are loc:


Hk,m+k ∙ (t1, ..., tm, u1, ..., uk)t = Ok,1
Din ipoteze rezultă că au loc egalităţile:
q q
tj  
i 1
sij , j  1, m ; uj   c , j  1, k
i 1
ij şi H k ,mk  (si1 , ...sim , ci1 , ..., cik ) t  Ok ,1 , i  1, q

Din acestea, înlocuind expresiile lui tj şi uj şi aplicând distributivitatea


înmulţirii faţă de sumă rezultă că avem:
q q q q
H k ,m  k  (s i1 , ...s im , c i1 , ..., c ik ) t  H k ,m  k  ( s i1 , ... s im ,  c i1 , ...,  c i1 ) t 
i 1 i 1 i 1 i 1
q q
  H k ,m  k (s i1 , ...s im , c i1 , ..., c ik )   O k ,1
t

i 1 i 1
Să considerăm, de exemplu, scrierea pe un suport magnetic a şirului de
caractere ASCII „ABCD”. Fiecare dintre cele patru caractere se vor
reprezenta pe câte 8 biţi. Aceste coduri ASCII, scrise în hexazecimal, sunt:

41 42 43 44
Drept cod liniar binar vom folosi codul (7, 4) dat ca exemplu în secţiunea 2.2.
Matricea de informaţie va avea q = 8 linii, câte una pentru fiecare bit al fiecărui
octet, deci fiecare octet este reprezentat pe o coloană. Fiind vorba de 4 octeţi,
matricea de informaţii va avea m = 4 coloane. Codul liniar binar (7, 4) va mai
adăuga şi el încă trei coloane pentru biţii lui de control, iar codul iterativ va mai
introduce încă o linie şi o coloană. Deci, blocul de informaţie va avea conţinutul:
0 0 0 0 | 0 0 0 | 0
1 1 1 1 | 1 1 1 | 1 

0 0 0 0 | 0 0 0 | 0
 
0 0 0 0 | 0 0 0 | 0
0 0 0 0 | 0 0 0 | 0
 
0 0 0 1 | 1 1 1 | 0
0 1 1 0 | 0 1 1 | 0
 
1 0 1 0 | 1 0 1 | 0
 
    |    | 
 0 0 1 0 | 1 1 0 | 1 

30
2.2.4 Codul lui Hamming
Codul lui Hamming este un cod autocorector bazat pe teste de paritate.
Versiunea cea mai simplă permite corectarea unui bit eronat. Celor m biţi de
informaţie li se adaugă k biţi de control al parităţii. Vom avea n = m+k biţi
necesari pentru transmiterea informaţiei.
Deoarece trebuie indicate n + 1 posibilităţi de eroare (inclusiv absenţa
erorii) prin cei k biţi de control, trebuie ca 2k  n + 1. Cele 2k posibilităţi de
de codificare pe k biţi servesc la determinarea poziţiei erorii, apoi se poate
corecta bitul eronat.
Tabelul următor permite determinarea lui k când se cunoaşte n:
m 0 0 1 1 2 3 4 4 5 6 7 8 9 10 ... 120
k 1 2 2 3 3 3 3 4 4 4 4 4 4 4 ... 8
n 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ... 128
De obicei se ia n  2k – 1 în loc de n < 2k – 1.
Dacă se numerotează biţii de la dreapta spre stânga pornind de la 1, biţii
de control (sau de paritate) sunt plasaţi pe poziţia puterilor lui 2 (biţii cu
numărul 1, 2, 4, 8, 16, ...). Fiecare bit de control efectuează control de
paritate (pară sau impară) asupra unui anumit număr de biţi de date. Se
determină astfel cei n biţi de transmis sau de stocat.
Exemplu: Dacă m  4 se poate construi un cod Hamming (CH) pe 7 biţi
(n  7), adăugând 3 biţi de control (k  3).
7 6 5 4 3 2 1
m4 m3 m2 k3 m1 k2 k1
Cei trei biţi de control sunt plasaţi pe poziţia puterilor lui 2:
k1  1; k2  2; k3  4.
Vom vedea acum, pentru fiecare bit al mesajului care sunt biţii de control
care permit verificarea parităţii sale.
7  (0111)2  4 + 2 + 1  7 este controlat de k3, k2, k1;
6  (0110)2  4 + 2  6 este controlat de k3, k2;
5  (0101)2  4 +1  5 este controlat de k3, k1;
4  (0100)2  4  4 este controlat de k3;
3  (0011)2  2+1  3 este controlat de k2, k1;
2  (0010)2  2  2 este controlat de k2;
1  (0001)2  1  1 este controlat de k1;
Problema se pune şi invers: care sunt poziţiile binare controlate de către
fiecare cod? Răspunsul este următorul:
k1 controlează biţii cu numerele 1, 3, 5, 7;
k2 controlează biţii cu numerele 2, 3, 6, 7;
k3 controlează biţii cu numerele 4, 5, 6, 7.

31
Când se recepţionează informaţia, se efectuează controlul de paritate.
Pentru fiecare bit de control se compară valoarea transmisă cu cea recalculată.
Dacă cele două valori sunt identice, se atribuie valoarea 0 unei variabile binare
Ai asociată bitului de control ki, altfel, Ai primeşte valoarea 1.
Valoarea zecimală a configuraţiei binare formată din variabilele Ak, Ak-1, ..., A1
furnizează poziţia bitului eronat, care se poate corecta.
Reluăm exemplul precedent:
Presupunem că: pentru k1, A1  1, pentru k2, A2  1, iar pentru k3, A3  0.
Eroarea se găseşte în poziţia (A3A2A1)2  (011)2  3.
Într-adevăr, k1 poate detecta o eroare în poziţiile 1, 3, 5, 7, k2 poate
detecta o eroare pe poziţiile 2, 3, 6, 7, iar k3 pe poziţiile 4, 5, 6, 7. O eroare
detectată de k 1 şi k 2 nu şi de k3 nu poate proveni decât din bitul 3.
Exemple:
(A3A2A1)2  (000)2 indică absenţa unei erori;
(A3A2A1)2  (001)2 indică eroare pe bitul 1;
(A3A2A1)2  (110)2 indică eroare pe bitul 6.
Exemplu de recepţionare a unui mesaj: (1011100)2. Dacă s-a utilizat un
CH cu paritate pară, să se reconstituie mesajul iniţial (n  7, k  3, m  4).
număr 7 6 5 4 3 2 1
tip m4 m3 m2 k3 m1 k2 k1
valoare 1 0 1 1 1 0 0
k1  0 controlează poziţiile 1, 3, 5, 7, nu se verifică, deci A1  1;
k2  0 controlează poziţiile 2, 3, 6, 7, se verifică, deci A2  0;
k3  0 controlează poziţiile 4, 5, 6, 7, nu se verifică, deci A3  1;
Adresa erorii (A3A2A1)2  (101)2  5. Bitul numărul 5, care este egal cu 1
este eronat. Mesajul iniţial corectat şi fără biţii de control este: (1001)2.

Calculul simplificat al codului lui Hamming (CHS)


Metoda Hamming poate simplifica calculul biţilor de control, astfel:
 se transformă în binar poziţiile din mesaj care conţin valoarea 1;
 se însumează modulo 2, astfel:
 pentru paritate pară: un număr par de 1 0, un număr impar
de 11 (sumă modulo 2 directă);
 pentru paritate impară: un număr par de 11, un număr impar
de 10 (sumă modulo 2 inversată).
Exemplu: Să codificăm mesajul (10101011001)2 cu paritate pară: m  11,
deci k  4 şi n  15.
număr 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1
tip m11 m10 m9 m8 m7 m6 m5 k4 m4 m3 m2 k3 m1 k2 k1
valoare 1 0 1 0 1 0 1 ? 1 0 0 ? 1 ? ?

32
Biţii cu valoarea 1 se găsesc pe poziţiile 15, 13, 11, 9, 7, 3, deci:
15  1 1 1 1
13  1 1 0 1
11  1 0 1 1
91 0 0 1
70 1 1 1
30 0 1 1
-----------
0 1 0 0  biţi de paritate
k4 k3 k2 k1
Mesajul codificat este deci (101010101001100)2.
Exemplu de recepţie a unui mesaj:
S-a primit mesajul următor: (101000101001100)2, codificat cu paritate
impară. Biţii cu valoarea 1 se găsesc pe poziţiile 15, 13, 9, 7, 4, 3.
15  1 1 1 1
13  1 1 0 1
91 0 0 1
70 1 1 1
40 1 0 0
30 0 1 1
----------  adunare modulo 2 inversată.
0 1 0 0
A4A3A2A1  eroare pe poziţia 4.
După corectarea erorii şi eliminarea codurilor de control, mesajul iniţial
este: (10100011001)2.

Codul lui Hamming şi erorile grupate


Metoda lui Hamming poate corecta în general doar un bit eronat, dar se
poate utiliza pentru detectarea şi corectarea erorilor multiple pe o secvenţă
de biţi aranjând mesajul sub formă matricială, codificând pe linie după
metoda HC şi transmiţând mesajul pe coloane.
De exemplu, pentru transmiterea mesajului „ Hamming” se codifică pe o linie
fiecare caracter în cod ASCII, completând cu biţii de control după metoda CH.
Dacă se produc erori grupate, pentru o secvenţă de biţi suficient de
scurtă, ( 7 pentru acest caz) atunci, efectuând transmisia pe coloană vom
avea un singur bit eronat pe linie, pe care-l putem corecta datorită biţilor de
control adăugaţi potrivit metodei lui Hamming.
În ultimii ani, codurile autocorectoare sunt din ce în ce mai utilizate
pentru a asigura integritatea informaţiilor stocate în memorie.
ASCII Cod Hamming (pentru fiecare literă)

33
11 10 9 8 7 6 5 4 3 2 1 (număr)
H  1001000 1 0 0 1 1 0 0 1 0 0 0
a  1100001 1 1 0 0 0 0 0 0 1 1 0
m  1101101 1 1 0 0 1 1 0 0 1 1 1
m  1101101 1 1 0 0 1 1 0 0 1 1 1
i  1101001 1 1 0 0 1 0 0 1 1 0 1
n  1101110 1 1 0 0 1 1 1 1 0 0 1
g  1100111 1 1 0 0 0 1 1 0 1 0 1

Un cod autocorector permite creşterea considerabilă a timpului mediu


între două defecţiuni care pot să apară: erorile nu apar decât atunci când
numărul lor depăşeşte capacitatea de corectare a codului respectiv. Erorile
care nu sunt corectate, cel puţin se pot detecta.

Detectarea erorilor grupate


În comunicaţiile la distanţă, erorile sunt mult mai frecvente decât în
interiorul calculatorului. Erorile consecutive pot fi extinse adesea la un bloc
întreg de biţi de informaţie.
Se vor utiliza în acest sens coduri care permit detectarea erorilor
grupate, corectarea acestora fiind adesea prea costisitoare.

Metoda codurilor polinomiale (CRC)


CRC Cyclic Redondant Coding este metoda cea mai folosită pentru
detectarea erorilor grupate. Înaintea transmiterii, informaţiei i se adaugă biţi
de control, iar pe baza acestora, dacă la recepţionarea mesajului se
detectează erori, atunci acesta trebuie retransmis.
O informaţie pe n biţi poate fi considerată ca lista coeficienţilor binari ai
unui polinom cu n termeni, deci de grad n-1.
Exemplu: 110001 x5 + x4 + 1;
Pentru a calcula biţii de control se va efectua un anumit număr de
operaţii cu aceste polinoame cu coeficienţi binari. Operaţiile se vor efectua
modulo 2, adunarea şi scăderea nu va ţine seama de cifra de transport, deci
toate operaţiile de adunare şi scădere sunt identice cu operaţia logică XOR.
Pentru generarea şi verificarea biţilor de control atât sursa cât şi
destinaţia mesajului utilizează un polinom generator G (x).
Dacă M (x) este polinomul corespunzător mesajului iniţial (de transmis), iar r
este gradul polinomului generator G (x), atunci algoritmul de construire şi verificare
a codurilor care se incorporează în mesajul de transmis este următorul:
1) se înmulţeşte M (x) cu xr (se adaugă r zerouri la sfârşitul mesajului);

34
2) Se efectuează împărţirea modulo 2: M(x)*xr/G(x)Q(x)+R(x)/G(x);
Câtul Q (x) se ignoră, iar restul R (x) conţine r biţi.
3) Se efectuează scăderea modulo 2: M (x) * xr – R (x)  T (x), iar T (x)
este polinomul care reprezintă mesajul de transmis. Polinomul ciclic
T (x)  Q (x) * G (x) este un multiplu al polinomului generator.
4) La recepţionarea mesajului se efectuează împărţirea T (x) /G (x):
a) dacă restul  0 nu sunt erori de transmisie;
b) altfel, s-au produs erori, deci mesajul trebuie retransmis.
Exemplu de transmitere a unui mesaj. Se doreşte transmiterea mesajului
101101 (6 biţi)  M (x) =x5 + x3 + x2 + 1.
Polinomul generator este: 1011 G (x) = x3 + x + 1 de grad r = 3.
1) Efectuăm înmulţirea: M (x) xr = 101101000 (se adaugă r = 3 zerouri
la M (x).
2) Realizăm împărţirea modulo 2: M (x)*xr/G (x):
1 0 1 1 0 1 0 0 0 1 0 1 1
1011 ---------
-------- 1 0 0 0 0 1  câtul Q(x)
000001000
1011
--------
0 0 1 1  R (x) = 0 1 1
3) Câtul Q (x) este ignorat. Pentru a realiza diferenţa modulo 2, M (x)
*xr – R (x) este suficientă adăugarea celor r biţi din R (x) la sfârşitul
mesajului M (x)  mesajul de transmis este T (x) = 101101011.
Exemplu de recepţionare a unui mesaj. S-a primit mesajul următor:
11010101. G (x) = 1011 (4 biţi)  G (x) = x3 + x + 1 de grad r = 3.
4) Se efectuează împărţirea T (x) / G (x).
1 1 0 1 0 1 0 1 1 0 1 1
1011 ---------
-------- 11110
01100
1010
--------
01111
1011
--------
01000
1011
--------
0 0 1 1 1 R (x) = 1 1 1

35
R (x)  0, s-au detectat erori de transmisie, mesajul se retransmite.
Cele mai utilizate polinoame generatoare G (x) sunt:
 CRC – 12  x12 + x11 + x3 + x2 + x + 1;
 CRC – 16  x16+ x15 + x2 + 1;
 CRC – CCITT  x16 + x12 + x5+ 1.

2.3 Elemente de logică numerică

Logica propoziţională este o algebră al cărei obiectiv iniţial este


modelarea raţionamentului.
Mai recent această algebră şi-a demonstrat utilitatea ca instrument de
concepţie (concepţia circuitelor calculatorului).
O a treia utilizare a logicii constă în a servi ca model de calcul pentru
limbajele de programare (Prolog).
Logica propoziţională este un model matematic care ne permite să
raţionăm asupra naturii adevărate sau false a expresiilor logice.
O propoziţie este un enunţ care poate lua una din cele două valori de
adevăr: adevărat sau fals. Simbolurile care pot reprezenta o propoziţie se
numesc variabile propoziţionale.

2.3.1 Expresii logice


O primă mulţime de expresii logice se defineşte recursiv astfel:
- sunt operanzi atomici:
 variabilele propoziţionale;
 constantele logice true şi false;
- Orice operand atomic este expresie logică;
- Dacă E şi F sunt expresii logice atunci E and F este expresie logică;
- Dacă E şi F sunt expresii logice atunci E or F este expresie logică;
- Dacă E este expresie logică atunci not E este expresie logică;
Prezentăm definiţia operatorilor logici and, or şi not.

and 0 1 or 0 1 not
0 0 0 0 0 1 0 1
1 0 1 1 1 1 1 1

Funcţii booleene
„Semnificaţia” unei expresii logice poate fi descrisă formal ca o funcţie
care dă o valoare adevărat sau fals pentru expresia întreagă pornind de la
valoarea argumentelor, numită funcţie logică sau booleană.

36
Tabele de adevăr
O funcţie booleană poate fi reprezentată în practică printr-o tabelă de
adevăr ale cărei linii corespund tuturor combinaţiilor de valori de adevăr
pentru argumente. Există o coloană pentru fiecare argument şi una pentru
valoarea funcţiei.
Figura următoare prezintă tabelele de adevăr pentru operaţiile logice
and, or, not, xor.
p q p and q p q p or q p not p p q p xor q
0 0 0 0 0 0 0 1 0 0 1
0 1 0 0 1 1 1 0 0 1 0
1 0 0 1 0 1 1 0 0
1 1 1 1 1 1 1 1 1

Tabela de adevăr a unei funcţii cu k argumente posedă 2k linii. Fiecare


linie asignează pentru funcţie valoarea 0 sau 1, deci există 22k funcţii.

Operatori logici suplimentari


 implicaţia  “ dacă p este adevărat atunci q este adevărat”;
 echivalenţa  “ dacă şi numai dacă“;
 operatorul nonand “ not (p and q)”, notat p nand q;
 operatorul nonor “ not (p or q)”, notat p nor q.
Figura următoare prezintă tabelele de adevăr pentru , , nand, nor.
p q pq p q p  q p q p nand q p q p nor q
0 0 1 0 0 1 0 0 1 0 0 1
0 1 1 0 1 0 0 1 1 0 1 0
1 0 0 1 0 0 1 0 1 1 0 0
1 1 1 1 1 1 1 1 0 1 1 0

Asociativitatea şi precedenţa operatorilor logici


Operatorii logici and şi or sunt asociativi şi comutativi şi vor fi grupaţi
de la stânga la dreapta. Ceilalţi operatori nu sunt asociativi.
Precedenţa operatorilor logici: not, nand, nor, and, or, , .

Funcţii booleene ale expresiilor logice


Vom construi expresii logice pornind de la tabelele de adevăr. Deşi se
pot defini o infinitate de expresii logice, de obicei, se va încerca pe cât
posibil să se găsească cea mai simplă expresie logică.

Notaţii prescurtate
and se reprezintă prin juxtapunerea operanzilor;

37
or se reprezintă prin +;
not se reprezintă prin  sau prin bararea variabilei.

Construcţia unei expresii logice din tabela de adevăr


Forma normală disjunctivă este o sumă logică de mintermi pentru
care funcţia ia valoarea logică adevărat (1). Un minterm este un produs
logic de literale (variabile propoziţionale) ale unei linii, astfel: dacă p are
valoarea 0 în coloana k, se utilizează p , altfel se utilizează p.
Forma normală conjunctivă este un produs logic de maxtermi pentru
care funcţia ia valoarea 0. Un maxterm este o sumă logică de literale ale
unei linii, astfel: dacă p ia valoarea 0 se utilizează p, altfel p .

2.3.2 Legi algebrice pentru expresii logice

Legi ale echivalenţei


1. Reflexivitate:  p  p  ;
2. Comutativitate:  p  q   q  p  ;
3. Tranzitivitate:  p  q  and q  r    p  r  ;
4. Echivalenţa negaţiilor:  p  q    p  q  ;

Legi similare aritmeticii


5. Comutativitate and: p  q  q  p ;
6. Asociativitate and: p  q  r    p  q   r ;
7. Comutativitate or:  p  q   q  p  ;
8. Asociativitate or:  p  q  r    p  q   r  ;
9. Distributivitate and faţă de or: p  q  r   p  q  p  r ;
10. 1 (true) este identitate pentru and: p  1  p ;
11. 0 (false) este identitate pentru or:  p  0   p ;
12. 0 este adsorbant pentru and: p  0  0 ;
13. Eliminare duble negaţii: p  p .

Diferenţe faţă de legile aritmeticii


14. Distributivitate or faţă de and:  p  q  r    p  q    p  r  ;
15. 1 este adsorbant pentru or: 1  p  1 ;
16. Idempotenţa operatorului and: p  p  p ;
17. Idempotenţa operatorului or: p  p  p ;

38
18. Subsumarea:
a)  p  p  q   p ;
b) p   p  q   p .
19. Eliminarea anumitor negaţii:
a) p   p  q   p  q ;
b)  p  p  q   p  q .
20. Legile lui de Morgan:
a) p  q  p  q ;
b) p  q  pq ;
c) p1  p2  ...  pn  p 1+ p 2+...+ p n;
d) p1  p2  ...  pn  p1  p2  ...  pn .

Legi ale implicaţiei


21.  p  q  and q  p    p  q  ;
22.  p  q    p  q  ;
23.  p  q  and q  r    p  r ;
24.  p  q   p  q.
Tautologii şi metode de demonstraţie
25. Legea terţului exclus:  p  p   1 ;
26. Analiza de caz:  p  q  and  p  q   q ;
27. Contrara reciprocei:  p  q   q  p  ;
28. Reducere la absurd:  p  0   p ;
29. Demonstraţie prin reducere:  p  1  p ;
Exemple:

1) Funcţii de o variabilă a:

a z0 z1 z2 z3 z0 = 0 constantă;
0 0 0 1 1 z1 = a identitate;
1 0 1 0 1 z2 = a negaţie;
z3 = 1 constantă;

2) Funcţii logice de 2 variabile a şi b:


00 01 10 11 ab

39
0 0 0 0 F0 = 0
0 0 0 1 F1 = a  b
0 0 1 0 F2 = a  b
0 0 1 1 F3 = a
0 1 0 0 F4 = a  b
0 1 0 1 F5 = b
0 1 1 0 F6 = a  b
0 1 1 1 F7 = a  b
1 0 0 0 F8 = a  b  a  b
1 0 0 1 F9 = a  b
1 0 1 0 F10 = b
1 0 1 1 F11 = a  b
1 1 0 0 F12 = a
1 1 0 1 F13 = a  b
1 1 1 0 F14 = a  b  a  b
1 1 1 1 F15 = 1

2.3.3 Porţi logice


Operatorii logici AND, OR şi NOT au fost reprezentaţi până acum într-
un sens abstract folosind tabele de adevăr şi expresii booleene.
Componentele fizice, sau circuitele digitale, ca acelea care realizează
operaţiile aritmetice sau fac alegeri într-un calculator, sunt construite dintr-
un număr de elemente primitive numite porţi logice. Porţile implementează
fiecare din funcţiile logice de bază despre care am vorbit. Aceste porţi sunt
„pietrele de temelie” ale designului digital. Poarta este un mic dispozitiv
electronic care calculează diverse funcţii de două valori. Mai simplu spus, o
poartă implementează o funcţie booleană simplă. Pentru a implementa fizic
fiecare poartă este nevoie de 1 până la 6 sau mai mulţi tranzistori, depinzând
de tehnologia care este folosită. Pe scurt, componenta fizică de bază a unui
calculator este tranzistorul, iar elementul logic de bază este poarta.

Simboluri pentru porţile logice


Examinăm iniţial cele trei porţi logice care corespund operatorilor logici
AND, OR şi NOT. Am discutat despre comportamentul funcţional al acestor
operatori booleeni. Figura următoare ilustrează reprezentarea grafică a
porţilor corespunzătoare operatorilor AND, OR şi NOT.

40
De observat cercul de la ieşirea porţii NOT. Cercul reprezintă operaţia de
complementare. O altă poartă este poarta sau-exclusiv (XOR), reprezentată de
expresia booleană xy. XOR este falsă când valorile de intrare sunt egale şi
adevărată altfel. Figura următoare ilustrează tabela de adevăr pentru XOR,
precum şi diagrama logică care îi specifică comportamentul.

Porţi universale
Alte două porţi sunt NAND şi NOR, care produc outputul complementar
pentru AND şi OR. Fiecare poartă are două simboluri logice diferite care pot fi
folosite pentru reprezentare. Figura următoare ilustrează diagramele logice pentru
NAND şi NOR şi tabelele de adevăr pentru a explica comportamentul funcţional
al fiecărei porţi.

Poarta NAND este adesea numită poartă universală, deoarece orice


circuit electronic poate fi construi folosind doar porţi NAND. Pentru a
demonstra acest lucru, figura următoare ilustrează o poartă AND, o poartă
OR şi una NOT folosind numai porţi NAND.

41
De ce să nu folosim porţile AND, OR şi NOT pe care le cunoaştem? Există
două motive pentru folosirea doar a porţilor NAND la construirea oricărui circuit.
Primul: porţile NAND sunt mai ieftin de construit decât celelalte. În al doilea
rând, circuitele integrate complexe sunt adesea mult mai uşor de construit
folosind aceleaşi elemente (de exemplu, câteva porţi NAND) decât o colecţie de
elemente de bază (de exemplu, o combinaţie de porţi AND, OR şi NOT).
De asemenea, se poate construi un circuit folosind numai porţi NOR.
Deoarece porţile NAND şi NOR sunt legate în general în acelaşi fel ca o
sumă de produse logice şi, respectiv, un produs de sume logice, se poate
folosi NAND pentru implementarea unei expresii în forma sumă de produse
şi NOR pentru expresii în forma produs de sume.

Porţi logice cu intrări multiple


În exemplele noastre de până acum toate porţile acceptau doar două
intrări. Porţile însă nu sunt limitate la doar două intrări. Există multe variaţii
între numărul şi tipul de intrări şi ieşiri permise de diverse porţi. De exemplu
putem reprezenta expresia x+y+z folosind o poartă OR cu trei intrări, ca în
figura următoare:

Figura următoare prezintă o poartă logică pentru implementarea expresiei


xyz .

2.3.4 Tabelele Karnaugh (TK)


Tabelele sau diagramele lui Karnaugh permit simplificarea funcţiilor
logice. Metoda se bazează pe inspectarea vizuală a tabelelor judicios
construite (metoda este utilă cu un număr de variabile  6).
TK se poate considera ca o transformare a tabelei de adevăr.

TK cu 2 variabile
Cele 4 căsuţe ale TK corespund celor 4 linii ale tabelei de adevăr:
 fiecare variabilă logică completează o linie sau o coloană;
 un produs de 2 variabile completează o căsuţă;

42
Pentru a completa TK pornind de la tabela de adevăr se atribuie valoarea
1 căsuţelor corespunzătoare stărilor din intrare în care funcţia are valoarea 1.
Metoda de simplificare constă din a încadra căsuţele ocupate, adiacente pe
aceeaşi linie sau coloană (suprapunerile parţiale sunt permise). Figura
următoare prezintă o TK cu 2 variabile.
a
a b z b 0 1

0 0 0 0 1
0 1 1
1 0 1 1 1 1
1 1 1
În urma reducerii avem vom obţine z = a+b.

TK cu 3 variabile
Tabela de adevăr a funcţiei logice de 3 variabile se transformă într-o TK
cu două dimensiuni, grupând două variabile pe linie sau coloană. Trecerea
de la o linie (coloană) la alta diferă printr-o singură variabilă (se consideră
tabela ca înfăşurătoarea unui cilindru.
Pentru construirea TK cu 3 variabile:
 fiecare variabilă completează un bloc de 4 căsuţe;
 un produs logic de două variabile completează un bloc de 2 căsuţe;
 un produs logic de 3 variabile completează o căsuţă.
Exemplu: f (a, b, c) = a b c  ab c  ab c  abc ;
b ac 00 01 11 10
0 1 1 1
1 1

În urma reducerii se obţine z  ac  b c .

TK cu 4 variabile
Se construieşte TK, precum înfăşurătoarea unui cilindru, atât orizontal
cât şi vertical, astfel:
 fiecare variabilă completează un bloc de 8 căsuţe;
 un produs logic de 2 variabile completează un bloc de 4 căsuţe;
 un produs logic de 3 variabile completează un bloc de 2 căsuţe;
 un produs logic de 4 variabile completează o căsuţă.
Exemplu:

43
z (a, b, c, d )  a b c d  a b c d  a b cd  a bc d 
abc d  ab c d  ab c d  a bcd  ab cd  a bcd  abcd
cd ab 00 01 11 10

00 1 1

01 1 1 1 1

11 1 1 1 1

10 1

Expresia simplificată este z  d  b c  a bc .


În general, metoda de simplificare a unei funcţii de 4 variabile prin TK
este următoarea:
 încadrarea căsuţelor cu 1 care nu sunt adiacente altora cu 1 şi deci
nu pot forma blocuri de 2 căsuţe;
 încadrarea căsuţelor care pot forma grupe de 2 căsuţe dar nu pot
forma blocuri de 4 căsuţe;
 încadrarea căsuţelor care pot forma grupe de 4 căsuţe dar nu pot
forma blocuri de 8 căsuţe;
 încadrarea grupelor de 8 căsuţe adiacente;
Pentru reducerea funcţiilor logice cu mai mult de 4 variabile trebuie
create mai multe tabele Karnaugh.

2.4 Memorii

O memorie este un dispozitiv capabil să înregistreze, să conserve şi să


restituie informaţii (codificate în binar în sistemul de calcul).

Ierarhia memoriilor
Figura următoare prezintă tipurile de memorie şi arată ierarhia existentă
între diferitele nivele de memorie.

44
Registre
CPU

memoria cache

memoria centrală

memoria de sprijin

memorii auxiliare

Se poate constata faptul că pe măsură ce ne îndepărtăm de CPU, timpul de


acces şi capacitatea memoriei cresc, în timp ce costul pe bit se diminuează.
a) registrele sunt elementele de memorie situate în unitatea centrală de
prelucrare (CPU) şi sunt caracterizate printr-o mare viteză, servind
în principal stocării operanzilor şi a rezultatelor intermediare. Vom
vorbi mai pe larg despre aceste memorii în subcapitolul următor.
b) memoria cache sau antememoria este o memorie rapidă, de
capacitate redusă (în raport cu memoria centrală) utilizată ca
memorie intermediară între CPU şi memoria centrală. Această
memorie permite minimizarea numărului de accese la memoria
centrală, realizând astfel câştig considerabil de timp.
c) memoria centrală este organul principal de aranjare a informaţiilor
utilizate de către CPU. Pentru execuţia unui program el trebuie să fie
încărcat (instrucţiuni + date) în memoria centrală. Aceasta este o
memorie pe semiconductoare al cărei timp de acces este mult mai
mare decât cel al registrelor sau memoriei cache.
d) memoria de sprijin serveşte drept memorie intermediară între
memoria centrală şi memoriile auxiliare. Memoria de sprijin este
prezentă în sistemele de calcul cele mai evoluate şi permite creşterea
vitezei de schimb a informaţiilor între cele două nivele.
e) memoriile auxiliare numite de asemenea şi memorii de masă, sunt
memorii periferice de mare capacitate şi cost relativ scăzut. Ele

45
servesc ca dispozitive de stocare permanentă şi utilizează pentru
aceasta suporturi magnetice (discuri, cartuşe, benzi) şi suporturi optice
(discuri optice) spre deosebire de nivelele mai apropiate de CPU care
fac apel la tehnologia semiconductoarelor.

Organizarea informaţiilor
Informaţiile pe care le prelucrează un sistem de calcul trebuie să se
adapteze unui anumit format, ale cărui caracteristici generale sunt următoarele:
a) Bitul, constituie unitatea de bază a informaţiei. Într-o memorie, cel
mai mic element de stocare este numit adesea punct de memorie: el
memorează un bit de informaţie.
b) Octetul, mai cunoscut sub termenul englez de byte, corespunde unei
succesiuni de 8 biţi.
c) Caracterul este o grupare de 6, 7, 8, ... biţi, permiţând codificarea
unui caracter alfanumeric sau a unui caracter special (!, , $, %, ^, &,
*, “, , , ...) potrivit convenţiilor de codificare: ASCII, EBCDIC etc.
d) Cuvântul word este o grupare de biţi constituind unitatea de
informaţie adresabilă în memoria centrală şi care variază de la un
sistem de calcul la altul. Valorile 32 şi 64 au tendinţa de a deveni
valori generale pentru lungimea unui cuvânt.
e) Înregistrarea record semnifică un bloc de date şi constituie
unitatea de informaţie stocată în memoria auxiliară a sistemului de
calcul (disc, bandă).
f) Fişierul file este o mulţime finită de înregistrări.

Caracterisicile memoriilor
a) Adresa este valoarea numerică desemnând un element fizic de
memorie (de exemplu adresa unui cuvânt în memoria centrală).
b) Capacitatea unei memorii corespunde numărului de instrucţiuni pe
care le poate conţine şi se poate exprima în funcţie de numărul de
biţi, octeţi sau cuvinte.
c) Timpul de acces este timpul în care se realizează o operaţie de
acces (citire sau scriere).
d) Ciclul de memorie este timpul minimal între două accese succesive
la memorie. Acesta este mai lung decât timpul de acces deoarece
cuprinde şi anumite operaţii de întreţinere, sincronizare, stabilizare
de semnale în circuite etc.
e) Volatilitatea caracterizează permanenţa informaţiilor într-o
memorie. O memorie volatilă îşi pierde conţinutul la producerea
unei întreruperi de curent, deci are nevoie de o alimentare constantă

46
cu energie electrică pentru a-şi conserva informaţiile. Memoria
centrală pe semiconductoare este volatilă spre deosebire de
memoriile magnetice auxiliare.
f) Debitul este numărul de informaţii citite sau scrise pe secundă.

Tipuri de acces la memorie


a) Accesul secvenţial: este accesul cel mai lent deoarece, pentru a
accesa o informaţie particulară trebuie parcurse toate informaţiile
care o preced (de exemplu, benzile magnetice);
b) Accesul direct: informaţiile posedă o adresă proprie care permite
accesarea lor în mod direct (de exemplu, memoria centrală, registrele);
c) Acces semi-secvenţial: este o combinaţie între accesul direct şi cel
secvenţial (de exemplu, pentru un disc magnetic, accesul la cilindru
este direct şi accesul la un sector este secvenţial);
d) Accesul prin conţinut (memorie asociativă): informaţiile sunt
identificate printr-o cheie şi căutarea se efectuează simultan pentru
toate poziţiile memoriei (de exemplu, memoria cache).

2.5 Unitatea centrală de prelucrare

Unitatea centrală de prelucrare sau procesorul central Central


Processing Unit = CPU, sau mai simplu procesor processor, are rolul de a
interpreta şi executa instrucţiunile programului pe un sistem de calcul.
CPU este un adevărat „creier” al sistemului, direct asociat cu memoria
unde sunt stocate instrucţiunile şi datele de prelucrat şi în acest context,
ansamblul CPU + memoria centrală este adesea specificat prin denumirea de
unitate centrală a sistemului de calcul.
Unitatea centrală de prelucrare se compune din două unităţi funcţionale
separate: unitatea aritmetică şi logică (UAL) şi unitatea de comandă şi
de control control unit.
Unitatea aritmetică şi logică este acea componentă a unităţii centrale de
prelucrare în care sunt executate operaţiile aritmetice şi logice.
Unitatea de comandă controlează funcţionarea tuturor celorlalte unităţi
(UAL, memorie, intrări/ieşiri), furnizându-le semnale de ritmicitate a
funcţionării şi de comandă.
Funcţionarea poate fi descrisă în modul următor: unitatea de comandă
caută în memoria centrală o instrucţiune transmiţând în acest sens spre
memorie o adresă şi o comandă. Instrucţiunea, înregistrată sub formă binară
la adresa dată, este transferată către unitatea de comandă, unde decodificarea
sa permite determinarea operaţiei cerute. Această informaţie este utilizată

47
pentru a genera semnalele corespunzătoare către UAL pentru declanşarea
execuţiei instrucţiunii. Datele de prelucrat vor fi de asemenea căutate în
memorie de către unitatea de control şi transferate direct unităţii de calcul.
Diferitele unităţi ale sistemului de calcul sunt interconectate prin sisteme de
cablare care transportă semnale electrice. Pentru a se evita legarea unei unităţi
cu toate celelalte, se utilizează linii exploatate în comun de către toate unităţile
sistemului de calcul. Se numeşte bus, ansamblul de linii capabile de a transmite
semnale corespunzătoare celor trei tipuri de informaţii: adrese, date şi comenzi.
Există la ora actuală arhitecturi bazate pe bus unic, pe care sunt conectate
toate organele sistemului de calcul. O asemenea structură, specifică
microcalculatoarelor, este ilustrată în figura următoare:

MEMORIE CPU

BUS
Adrese Date Comenzi

INTRĂRI IEŞIRI

În general, interconexiunile sunt asigurate prin bus-uri specializate: bus-


memorie, bus de intrare/ieşire etc. Bus-ul poate fi utilizat de către toate
unităţile care-i sunt ataşate dar nu mai mult decât două simultan, ceea ce
ridică probleme de aşteptare şi arbitraj al cererilor de utilizare.

Unitatea de comandă
Unitatea de comandă este mulţimea tuturor dispozitivelor de coordonare
a funcţionării sistemului de calcul în vederea executării secvenţei de operaţii
specificate prin instrucţiunile programului.
Principalele dispozitive ale unităţii de comandă care vizează căutarea în
memorie şi decodificarea unei instrucţiuni (ciclul de căutare), sunt:
a) contorul ordinal (CO), este un registru care conţine adresa din
memorie unde este stocată instrucţiunea de căutat;
b) registrul instrucţiune (RI), primeşte instrucţiunea de executat;
c) decodificatorul codului operaţiei, care determină ce operaţie trebuie
să fie efectuată, dintre toate cele posibile;
d) secvenţatorul, care generează semnale de comandă;
e) ceasul intern, sau orologiul, care emite impulsuri electrice
uniforme, sincronizând astfel toate acţiunile unităţii centrale.

48
Circulaţia informaţiilor în timpul unui ciclu de căutare fetch cycle:

2
RA Memorie RC

CO RI

Decodificator

5
4

Orologiu Secvenţator

Etapele ciclului de căutare (corespunzând numerelor încercuite în figura


de mai sus) pot fi rezumate astfel:
1) transferul adresei noii instrucţiuni din CO către RA, registrul de
adresă al memoriei memory adress register;
2) un semnal de citire, generat de către unitatea de comandă, provoacă
transferul instrucţiunii căutate în RC (registrul cuvânt), care
funcţionează ca un registru tampon pentru toate informaţiile citite
(sau scrise în) din memorie;
3) transferul instrucţiunii în RI (instrucţiune = cod operaţie + adresă
operand);
4) adresa operandului este trimisă către RA, iar codul operaţiei este
transmis decodificatorului care determină tipul operaţiei solicitate şi-
l transmite secvenţatorului printr-un semnal pe linia de ieşire
corespunzătoare;
5) CO este incrementat în vederea ciclului următor de căutare.
Ciclul de căutare este imediat urmat de ciclul de execuţie, în timpul căruia
operaţia specificată prin instrucţiune este efectuată de către unitatea de calcul.

49
Secvenţa exactă a acţiunilor coordonate de către secvenţator va depinde
de tipul operaţiei; în general, în timpul unui ciclu de execuţie, informaţia va
circula potrivit schemei următoare:

2
RA Memorie RC

Unitate de UAL
comandă 1
Acumulator

Secvenţator 3

Un ciclu de execuţie va cuprinde în mod normal următoarele etape:


1) secvenţatorul începe să trimită semnale de comandă către memorie
pentru citirea operandului la adresa deja stocată în RA şi realizează
transferul către RC;
2) transferul conţinutului din RC către UAL, mai precis către registrul
acumulator, sau oricare alt registru destinat operaţiei specificate. În
anumite cazuri, de exemplu, memorarea unui rezultat, conţinutul
registrului acumulator se va transfera către RC, iar pentru o instrucţiune
de salt, câmpul de adresă al instrucţiunii va trebui transferat în CO;
3) operaţia este efectuată sub controlul secvenţatorului.
Atunci când ciclul de execuţie este încheiat, unitatea de comandă trece
imediat la ciclul de căutare următor, luând în considerare noua instrucţiune
indicată prin adresa conţinută în CO.

Nivele de programare
Pentru a scrie un program, utilizatorul poate utiliza unul dintre limbajele
de programare cunoscute: Fortran, Pascal, Ada, Asamblor etc. Sistemul de
calcul nu poate înţelege decât propriul său limbaj, limbajul maşină, cu
mulţimea sa de instrucţiuni.
În programare, se utilizează termenul limbaj pentru a indica o mulţime de
instrucţiuni şi de reguli sintactice care permit scrierea codului sursă al
programului. Deoarece sistemul de calcul execută doar programe scrise în cod
maşină sau cod obiect, apare necesitatea traducerii codului sursă în cod obiect,
care se realizează automat cu ajutorul compilatoarelor şi asambloarelor.
50
Limbajele de programare se poate prezenta pe mai multe nivele, cele
superioare fiind mai apropiate de limbajul utilizatorului, iar cele inferioare
fiind mai bine adaptate caracteristicilor sistemului de calcul. Situaţia actuală
este sintetizată în figura următoare:

limbaje evoluate

nivel asamblor

instrucţiuni maşină

micro-instrucţiuni

nivelul comenzilor
electronice

Structura instrucţiunilor la nivel maşină


Sistemele de calcul sunt capabile să efectueze un anumit număr de
operaţii simple, de exemplu adunarea a două numere, testarea semnului unei
valori numerice, copierea conţinutului unui registru în alt registru, stocarea
în memorie a rezultatului unei operaţii etc.
O instrucţiune maşină trebuie să furnizeze pentru CPU toate informaţiile
pentru declanşarea unei operaţii elementare. Ea trebuie să conţină un cod al
operaţiei care este esenţial pentru specificarea tipului acţiunii dorite. În plus,
instrucţiunea mai trebuie să conţină una sau mai multe adrese, de exemplu,
adresa operandului (sau operanzilor), adresa unde se depune rezultatul,
adresa de căutare a instrucţiunii următoare.
De aceea, o instrucţiune în formatul unei instrucţiuni maşină va comporta
un câmp de cod operaţie şi până la patru câmpuri de adresă.
51
Un sistem de calcul funcţionează pe n adrese, n = 0, 1, 2, 3, 4, dacă
majoritatea instrucţiunilor sale conţin n adrese în câmpul de adrese.
Setul şi structura instrucţiunilor maşină caracterizează arhitectura
fundamentală a sistemelor de calcul. În acest context, dacă sistemele primei
generaţii utilizau frecvent formate pe mai multe adrese ale instrucţiunilor,
astăzi, datorită creşterii considerabile a capacităţii de memorare, se preferă
instrucţiuni pe o adresă.
Trecerea la instrucţiunea următoare de executat se realizează prin
utilizarea unui contor ordinal care se incrementează cu 1 la fiecare operaţie
şi acceptă execuţia secvenţială a instrucţiunilor.
Pentru a se evita reţinerea adresei rezultatului într-o locaţie separată,
acesta se poate memora în locul unui operand, utilizând un registru special,
acumulatorul: al doilea operand se găseşte deja în registrul acumulator
(încărcat prin instrucţiunea precedentă) şi rezultatul operaţiei va fi stocat de
asemenea în registrul acumulator.
Exemplul următor, de programare a unei maşini pe o adresă, prezintă
secvenţa instrucţiunilor maşină / asamblor pentru evaluarea următoarei
expresii aritmetice: A = B  (C + D  E – F / G).
1. LOAD F (LOAD = încărcă în registrul acumulator)
2. DIV G (DIV = împarte conţinutul acumulatorului)
3. STA T1 (STA = stochează conţinutul acumulatorului)
4. LOAD D
5. MPY E (MPY= multiplică conţinutul acumulatorului)
6. ADD C (ADD = adaugă la conţinutul acumulatorului)
7. SUB T1 (SUB = scade din conţinutul acumulatorului)
8. MPY B
9. STA A
Pentru a ilustra utilizarea unei maşini pe zero adrese va trebui utilizată o
structură de date specială numită stivă stack (sau memorie LIFO = Last In,
First Out), operanzii găsindu-se în cele două poziţii superioare şi rezultatul
fiind plasat în vârful aceleiaşi stive.
Se poate descrie astfel secvenţa instrucţiunilor corespunzătoare evaluării
expresiei din exemplul anterior: A = B  (C + D  E - F / G).
1. LOAD B Stiva = B
2. LOAD C Stiva = B; C
3. LOAD D Stiva = B; C; D
4. LOAD E Stiva = B; C; D; E
5. MPY Stiva = B; C; D  E
6. ADD Stiva = B; C + D  E
7. LOAD F Stiva = B; C + D  E; F 

52
8. LOAD G Stiva = B; C + D  E; F; G 
9. DIV Stiva = B; C + D  E; F / G 
10. SUB Stiva = B; C + D  E – F / G 
11. MPY Stiva = B  (C + D  E – F / G) 
12. STA A Stiva =  

Setul instrucţiunilor
Fiecare tip de sistem de calcul posedă un set de instrucţiuni de bază, care
variază de obicei între 50 şi 250. La ora actuală există două mari tendinţe în
ceea ce priveşte setul de instrucţiuni de bază:
a) Arhitecturile RISC Reduced Instruction Set Computer
preconizează un număr mic de instrucţiuni elementare într-un format
fix, uşor de realizat din punct de vedere material (hardware) şi cu o
execuţie rapidă, ceea ce implică un secvenţator cablat şi un
compilator capabil să exploateze bine caracteristicile sistemului (de
exemplu, utilizarea pe o scară largă a registrelor şi limitarea
acceselor la memoria centrală);
b) Arhitecturile CISC Complex Instruction Set Computer sunt
bazate pe un set bogat de instrucţiuni, de talie variabilă, oferind
astfel instrucţiuni compuse, ca de exemplu, calculul rădăcinii pătrate
sau înmulţire în virgulă mobilă dublă precizie. În general aceste
sisteme sunt prevăzute cu secvenţator multiprogramat.
Instrucţiunile care pot face parte din setul de instrucţiuni de bază ale
oricărui sistem de calcul pot fi clasate în şase grupe, astfel:
a) transfer de date (Load, Move, Store, transfer de date între două
registre sau între memoria principală şi un registru);
b) operaţii aritmetice (cele patru operaţii în virgulă fixă sau mobilă, în
simplă sau multiplă precizie);
c) operaţii logice (AND, OR, NOT, XOR etc.);
d) control de secvenţă (salturi condiţionate şi necondiţionate, apel de
subprograme etc.);
e) intrări/ieşiri (Read, Write, Print etc.);
f) operaţii diverse ( decalări, conversii de format, incrementări de
registre etc.).

Registrele CPU
Numărul şi tipul registrelor pe care le posedă CPU constituie o
caracteristică determinantă a arhitecturii sale şi au o influenţă importantă
asupra programării.

53
Deşi structura registrelor CPU diferă de la un constructor la altul, totuşi,
funcţiunile de bază realizate prin diverse registre CPU sunt în general
aceleaşi. În continuare vom descrie principalele registre CPU:
a) Contorul ordinal (CO) PC=Program Counter conţine adresa de
memorie a următoarei instrucţiuni de executat. El este incrementat
automat de către sistem după fiecare utilizare (programatorul nu are
acces direct la CO). Programul este executat în secvenţă, cu excepţia
situaţiilor în care conţine o instrucţiune de modificare a secvenţei
(de exemplu, o instrucţiune de salt sau de ramificare), caz în care
noua adresă va înlocui conţinutul contorului ordinal.
b) Acumulatorul (Rac) este un registru foarte important al UAL, care,
în majoritatea operaţiilor aritmetice şi logice conţine unul dintre
operanzi înainte de execuţie şi rezultatul după execuţie. Registrul
acumulator poate fi de asemenea utilizat ca un registru tampon în
operaţiile de intrare/ieşire. În general Rac are aceeaşi talie ca şi un
cuvânt-memorie, dar cele mai multe sisteme de calcul admit
extinderea registrului acumulator (registrul Q) pentru a conţine
rezultatul unei înmulţiri, câtul şi restul unei împărţiri, sau poate
conţine biţii cei mai puţin semnificativi în cadrul unei operaţii în
virgulă mobilă dublă precizie;
c) Registrele generale general purpose register permit salvarea
informaţiilor utilizate în mod frecvent de către program sau a
rezultatelor intermediare, ceea ce conduce la accelerarea execuţiei
programului prin reducerea numărului de accese la memoria
centrală;
d) Registrele de index sau de indice (XR) index register se pot
utiliza ca registre generale pentru salvări şi contorizări, posedând în
plus o funcţie specială, de mare utilitate în manipularea tablourilor
de date. Registrele de index pot fi utilizate pentru manipularea
adreselor corespunzător unei forme particulare de adresare numită
adresare indexată;
e) Registrele de bază (Rb) base registers sunt utilizate ca registre de
index pentru calculul adreselor efective (adresare bazată) şi în
acest sens ele sunt concepute să conţină o adresă de referinţă care
trebuie adăugată la conţinutul câmpului de adresă al instrucţiunii
pentru a obţine adresa efectivă;
f) Registrul de stare PSW = Program Status Word, numit de
asemenea registru condiţie, conţine anumiţi biţi care indică starea
unei condiţii particulare în CPU. De exemplu, bitul indicator Z indică
dacă rezultatul operaţiei efectuate este egal cu zero, bitul indicator C

54
indică o depăşire de capacitate în Rac etc. Aceşti biţi pot fi testaţi prin
program pentru determinarea secvenţei de instrucţiuni de urmat;
g) Registrul pointer de stivă SP = Stack Pointer este utilizat pentru
a simula o stivă în memoria centrală. Registrul SP funcţionează ca
un registru de adresă de memorie (RA) şi conţine în orice moment
adresa corespunzătoare vârfului stivei, deci, când se încarcă un
cuvânt în stivă adresa sa se înscrie în SP, iar citirea din stivă se face
pornind de la adresa indicată de pointerul SP;
h) Registrele specializate sunt specifice anumitor sisteme de calcul şi
sunt destinate operaţiilor particulare, de exemplu, registre de
decalare shift registers, registre pentru operaţii aritmetice în
virgulă mobilă floating point registers etc.

Adresarea operanzilor
Câmpul de adresă al unei instrucţiuni nu conţine de fiecare dată adresa
efectivă a unui operand şi de aceea, pentru facilitarea activităţii de
programare sunt puse la dispoziţie mai multe metode de adresare a
operanzilor, cunoscute sub numele de moduri de adresare, specificate în
formatul instrucţiunilor printr-un bit care indică modul folosit.
Printre modurile de adresare, cele mai importante sunt:
a) adresare directă: câmpul de adresă al instrucţiunii conţine adresa
efectivă a operandului;
b) adresare indirectă: câmpul de adresă al instrucţiunii conţine adresa
la care găseşte adresa efectivă a operandului (pot exista mai multe
nivele de indirectare);
c) adresare imediată: câmpul de adresă al instrucţiunii conţine chiar
operandul;
d) adresare implicită: codul operaţiei indică locul unde se găseşte
operandul (de exemplu, maşini pe zero adrese);
e) adresare indexată: adresa efectivă = conţinutul câmpului de adresă
al instrucţiunii + conţinutul registrului de index;
f) adresare bazată: adresa efectivă = conţinutul câmpului de adresă al
instrucţiunii + conţinutul registrului de bază;
g) adresare relativă: asemănătoare adresării bazate, dar utilizează
conţinutul registrului CO ca adresă de bază.

Exemple de adresare
Pentru simplificarea scrierii, în exemplele următoare vom utiliza simboluri ca:
a, b, c, alfa etc. pentru a indica anumite date şi prescurtări precum: IM (adresare
imediată), I (adresare indirectă), XR1 (registrul de index nr. 1), B1 (registrul de

55
bază nr. 1). Ne propunem să arătăm care este efectul pe care-l au asupra
conţinutului registrului acumulator diferitele moduri de adresare utilizate.
Conţinutul memoriei şi al câtorva registre este prezentat în tabela următoare:

Starea registrelor şi a memoriei


adresa conţinut adresa conţinut
100 a 300 alfa
101 b 301 beta
102 c 302 gama
103 d XR1 1
200 300 B1 100
201 302 B2 200
În tabela următoare sunt prezentate exemple de operaţii care utilizează
registrul acumulator, modurile de adresare fiind specificate după câmpul de
adresă al instrucţiunii.
Efectul diferitelor moduri de adresare este prezentat în continuare:

Instrucţiune Conţinutul Rac


LOAD 100 a
LOAD 100, IMM 100
LOAD 200, I alfa
LOAD 200, XR1 302
LOAD 200, XR1, I gama
LOAD 200, I, XR1 beta
LOAD 3, B1 d
LOAD 1, B2 302
Notăm cu ADR numărul de biţi din câmpul de adresă al unei instrucţiuni
şi fie 2n capacitarea memoriei centrale. Pot exista trei situaţii:
a) ADR = n: memoria fizică este accesibilă în totalitate şi orice metodă
de adresare poate fi utilizată;
b) ADR < n: ADR nu este suficient pentru a adresa toată memoria şi în
acest caz se poate utiliza metoda de adresare bazată, dacă registrul
de bază este suficient de mare (n biţi). În acest sens, se poate diviza
memoria în blocuri de o asemenea mărime încât ADR să poată
adresa complet un bloc. Câmpul de adresă al instrucţiunii va conţine
deplasamentul offset în interiorul blocului, iar adresa de început a
blocului va fi conţinută în registrul de bază. Adresa efectivă se va
calcula prin însumarea conţinutului registrului de bază cu conţinutul
câmpului de adresă al instrucţiunii.

56
c) ADR > n: ADR poate adresa poziţii de memorie care nu există în
memoria fizică, ceea ce oferă posibilitatea extinderii memoriei
principale spre memoriile auxiliare, de exemplu, discuri magnetice
(noţiunea de memorie virtuală).

Unitatea aritmetică şi logică (UAL)


Unitatea aritmetică şi logică, specifică sistemelor de calcul moderne,
este capabilă să realizeze o mare varietate de operaţii.
Anumite operaţii nu utilizează decât un singur registru şi un singur
operand, de exemplu, complementarea logică, decalarea, incrementarea etc.,
pe când alte operaţii folosesc doi operanzi, de exemplu, adunarea, scăderea,
operaţiile logice AND, OR, XOR etc.
Sistemele de calcul specializate pe aplicaţii cu caracter tehnico-ştiinţific
oferă o întreagă gamă de operaţii în virgulă mobilă în simplă şi dublă
precizie. Microcalculatoarele posedă un număr mai restrâns de instrucţiuni
specifice operaţiilor cele mai simple, lăsând în seama programării operaţiile
mai complexe, ca de exemplu, înmulţirea, împărţirea, extragerea rădăcinii
pătrate, operaţiile în virgulă mobilă etc.
Orice prelucrare de date are loc în cadrul UAL, unde se găsesc toate
circuitele capabile să efectueze operaţiile elementare care stau la baza
oricărui algoritm. UAL este total subordonată unităţii de comandă care
declanşează, controlează şi sincronizează orice activitate a UAL.

2.6 Unităţile de intrare/ieşire

Funcţiunea de bază a unui sistem de calcul este prelucrarea informaţiei.


Am văzut cum se realizează această funcţiune la nivelul memoriei centrale şi
a unităţii centrale de prelucrare.
Comunicarea sistemului de calcul cu lumea exterioară este realizată prin
intermediul unităţilor de intrare/ieşire input/output, sau I/O.
Vom prezenta în continuare modalităţile prin care sistemul de calcul
achiziţionează informaţia furnizată de mediul său exterior şi restituie
rezultatele prelucrării acestei informaţii.
În ultimii ani, tehnica intrărilor/ieşirilor a fost mult dezvoltată,
echipamentul intrărilor/ieşirilor este astăzi mai costisitor chiar şi decât
unitatea centrală şi ocupă mai mult spaţiu decât orice altă componentă a
sistemului de calcul.
Dacă sistemele de calcul din prima generaţie utilizau informaţii preluate
prin manipularea întreruptoarelor sau a benzii de hârtie perforată, în continuare
se vor utiliza tastaturi alfanumerice, cartele perforate, benzi şi cartuşe

57
magnetice, discuri şi dischete magnetice, discuri optice, ecrane video, mouse-
uri, creioane optice, cititoare optice de caractere sau de coduri specializate.
Tehnica ieşirilor a fost de asemenea considerabil dezvoltată. S-a trecut
astfel de la lămpile intermitente ale anilor ‘50, la ecranele color şi
imprimantele laser ale sistemelor contemporane.

Terminale interactive
Un terminal interactiv este un echipament periferic permiţând
utilizatorului o comunicare în ambele sensuri cu sistemul de calcul. Unitatea
de intrare este un dispozitiv interactiv precum tastatura keyboard sau
mouse-ul, iar unitatea de ieşire este un ecran de vizualizare display bazat
de obicei pe tehnica tubului catodic CRT.
Tastatura este dispozitivul interactiv prin excelenţă pentru toate
aspectele referitoare la tratarea unui text. Pentru o manipulare mai uşoară a
obiectelor pe ecran se utilizează mouse-ul.
Tastatura unui sistem de calcul este asemănătoare cu cea a unei maşini de
scris care realizează imprimarea pe o foaie de hârtie a caracterelor în urma
apăsării tastelor.
Prin acţionarea unei taste este lansat un semnal electronic care este
codificat în mod specific de exemplu în cod ASCII, iar caracterul
corespunzător tastei este afişat pe ecranul sistemului de calcul.

Ecrane alfanumerice
Un ecran alfanumeric se limitează la afişarea caracterelor distribuite pe un
anumit număr de linii, fiecare linie fiind compusă din mai multe sute de puncte.
Fiecare caracter este format dintr-o configuraţie de puncte alese conform
unei anumite grile, generând astfel o matrice de puncte.
Ecranul conţine în general o pagină de text organizată în 24 de linii şi 80
de coloane.

Ecrane grafice
Ecranele grafice permit atât afişarea caracterelor cât şi afişare de
imagini sau desene.
Prin apariţia şi dezvoltarea interfeţelor utilizatori - ecrane grafice bazate
pe folosirea ferestrelor şi pictogramelor, ecranele grafice au înlocuit ecranele
alfanumerice. Cele mai cunoscute ecrane grafice sunt:
a) Ecrane cu baleiaj TV la care ecranul este divizat în mici domenii
elementare (pixeli) care formează un număr de linii şi de coloane.
Evoluţia ecranelor cu baleiaj a cunoscut următoarele etape:

58
 ecranele monocrome, care afişează imagini binare (bitmap),
unde fiecare element este reprezentat printr-un bit;
 ecranele cu nivele de gri, care pot afişa imagini pixmap, în
care fiecare element de imagine poate avea un anumit nivel de
gri (8 biţi pot reprezenta 256 nivele de gri);
 ecranele color, permit afişarea imaginilor în culori, dar pentru
aceasta sunt necesare memorii-imagine mai mari, deoarece
pentru fiecare element de imagine trebuie indicate valorile
celor trei culori de bază (bleu, verde şi roşu).
b) Ecrane vectoriale, care realizează vizualizarea prin adresarea
punctuală a ecranului în locul unui baleiaj sistematic. Se utilizează
un fascicol ca “stilou” pentru trasare curbe conform unui parcurs
definit printr-o secvenţă de comenzi stocate într-o memorie locală.
Ecranele grafice sunt adaptate aplicaţiilor unde domină liniile,
structurile filiforme, desenele prin trasaj (contur), fără o eficienţă
deosebită în reproducerea imaginilor pline (fotografii);
c) Ecrane plate. Miniaturizarea produselor electronice a antrenat
realizarea şi dezvoltarea afişajelor pe ecrane plate, mai mici şi mai
puţin fragile decât tuburile catodice. Tehnici, ca de exemplu,
cristalele lichide sau ecrane cu plasmă au devenit competitive.

Imprimante
Tehnicile de imprimare au evoluat considerabil, la ora actuală există o
mare varietate de imprimante, acoperind un interval extins de preţuri şi de
performanţe. Imprimarea poate fi alb-negru sau color, principalele
procedee de imprimare color fiind jetul de cerneală, transfer termic sau
sublimare termică.
Imprimantele color utilizează trei culori primare galben, cyan, magenta,
ca şi negru, ceea ce permite crearea unei vaste palete de culori.
Putem prezenta o variantă de clasificare a imprimantelor:
a) Imprimante cu impact, încă utilizate în administraţie datorită
posibilităţii de a realiza copii carbon:
 teleimprimatoarele: capul mecanismului de imprimare are forma
unui cilindru pe care sunt gravate caracterele; între cilindru şi hârtia
de imprimat se găseşte o bandă îmbibată de cerneală;
 imprimantele Boole: caracterele sunt înscrise pe o sferă;
 imprimantele matriciale (prin puncte): caracterele sunt
compuse pornind de la punctele unei grile (matrice) de 7  9
sau 9  13, potrivit calităţii de imprimare alese;

59
b) Imprimantele fără impact, unde calitatea de imprimare este dată de
densitatea punctelor imprimate, care se exprimă în dpi dots per inch:
 imprimante termice: se aseamănă cu imprimantele matriciale
dar în locul lovirii unei benzi, se realizează încălzirea unei
suprafeţe de hârtie specială, sensibilă la căldură. Funcţionarea
este silenţioasă, iar în ceea ce priveşte imprimarea termică
color, sunt cunoscute două tehnologii: transfer termic şi
sublimare termică, ambele utilizând un rulou de celofan
acoperit de o cerneală în stare solidă, compusă dintr-o
succesiune de regiuni de culoare galbenă, cyan, magenta;
 imprimante cu jet de cerneală: sunt silenţioase şi au viteza de
imprimare comparabilă cu cea a imprimantelor termice, putând
imprima orice simbol sau grafism. Principiul de funcţionare
constă în crearea unui fascicol de picături de cerneală dirijate
asupra hârtiei cu o mare precizie. Calitatea de imprimare este
foarte bună, rezoluţia variază între 200 dpi şi 1200 dpi;
 imprimante laser: utilizează metode şi procedee
electrostatice. Se formează o imagine electrostatică pe un
tambur fotoconductor, tamburul trece prin faţa staţiei de
dezvoltare unde cerneala încărcată electric este atrasă numai de
punctele precedent încărcate. Imaginea este transferată pe
hârtie prin frecarea acesteia pe tambur. Această tehnică nu
necesită hârtie de calitate superioară, rezoluţia variază între
300 şi 2000 dpi (standard 600 dpi).

Digitalizoare
Digitalizoarele scanners sunt echipamente periferice care permit
„numerizarea” unei imagini pornind de la o copie pe suport solid (hârtie).
Rezultatul digitalizării este o imagine digitală stocată într-un fişier.

Arhitecturi şi proceduri de intrare/ieşire


Unitatea centrală comunică cu unităţile periferice prin intermediul
subsistemului de intrare/ieşire.
Pentru a efectua o operaţie de intrare/ieşire, în CPU se execută o
instrucţiune de intrare/ieşire. CPU preia iniţiativa realizării oricărei intrări
sau ieşiri, şi în funcţie de natura legăturii între CPU şi echipamentul periferic
implicat, se stabileşte o legătură directă CPU-periferic sau se atribuie sarcina
schimbului unui dispozitiv subordonat dar capabil să lucreze de manieră
autonomă, ca de exemplu, canal de intrare/ieşire sau acces direct la
memorie DMA: Direct Memory Access.

60
În cazul legăturii directe între CPU şi periferic apare problema diferenţei
enorme între vitezele de lucru ale celor două dispozitive, CPU rămâne blocat
pe toată durata transferului de informaţie.
În vederea utilizării raţionale a CPU, se utilizează tehnica întreruperii
programului. Metoda constă în introducerea unui semnal numit întrerupere
interrupt trimis spre CPU de către perifericul gata să efectueze un schimb
elementar, de exemplu, transferul unui octet. Acest semnal provoacă
întreruperea programului în curs de execuţie, CPU se ocupă de transfer prin
activarea unui program special (program de serviciu de întrerupere), iar
după efectuarea transferului, CPU reia programul întrerupt.
Abordarea cea mai economică constă în suspendarea programului în
execuţie timp de un ciclu-memorie, fără un efect deosebit asupra timpului
de execuţie. Această metodă se materializează prin utilizarea canalelor de
intrare/ieşire sau acces direct la memorie DMA.

Sistemul de întreruperi
Întreruperea este un semnal electronic generat de către o unitate
funcţională, de exemplu, canal sau controler de periferice, şi acest semnal
este transmis spre CPU pentru a provoca o ruptură de secvenţă în vederea
execuţiei unui program prioritar, care tratează cauza întreruperii.
Sistemul de întrerupere, încorporat în CPU la nivelul secvenţatorului,
este dispozitivul care înregistrează semnalele de întrerupere trimise către
CPU, ale căror cauze pot fi:
a) interne în raport cu CPU, de exemplu: depăşire de capacitate
(overflow), coduri de operaţii inexistente, erori de adresare, utilizare
abuzivă a instrucţiunilor privilegiate, pană de curent.
b) externe în raport cu CPU, de exemplu: starea unei unităţi periferice,
sfârşitul unui transfer de date.
Tratarea unei întreruperi se realizează prin următoarele acţiuni:
a) oprirea execuţiei programului în curs;
b) salvarea stării sistemului;
c) executarea programului de serviciu de întrerupere;
d) restaurarea stării sistemului;
e) reluarea execuţiei programului întrerupt.
Diversele cauze ale întreruperilor sunt afişate într-un vector de
indicatori asociat sistemului de întrerupere, iar programul care tratează
întreruperea trebuie să testeze aceşti indicatori.
În sistemele evoluate, fiecare întrerupere are asociată o adresă în
memoria centrală, iar ruptura de secvenţă este realizată prin transferul în
contorul ordinal a adresei unde se găseşte programul de serviciu.

61
Majoritatea sistemelor de calcul moderne sunt prevăzute cu sisteme de
întrerupere ierarhizate priority interrupt systems, acestea fiind sistemele cu
nivele de prioritate.
Problemele care trebuiesc rezolvate sunt următoarele:
 sosirea mai multor semnale de întrerupere în timpul execuţiei unei
instrucţiuni;
 sosirea unui semnal de întrerupere în timpul execuţiei unui program
de prelucrare a unei întreruperi anterioare.
În aceste sisteme, fiecare nivel este asociat unui anumit număr de
întreruperi, fiecărui nivel îi corespunde un anumit nivel de prioritate, iar orice
program poate fi întrerupt în vederea realizării unei întreruperi mai prioritare.
Sistemele de întrerupere cele mai elaborate sunt cele care fac parte din
sistemele de calcul orientate către aplicaţii de conducere a proceselor
industriale process control sau de achiziţionare de date data acquisition.
Un sistem de întrerupere modern trebuie să permită programatorului
următoarele acţiuni:
 invalidarea/activarea disable/enable sistemului de întrerupere;
 mascarea/demascarea individuală a întreruperilor;
 stabilirea unei ierarhii în mulţimea cauzelor intreruperilor şi
definirea mai multor nivele de prioritate, de preferinţă dinamic;
 asocierea unui program specific fiecărei întreruperi, permiţând
acţiuni elementare realizabile într-o singură instrucţiune;
 posibilitatea de utilizare a tuturor registrelor care caracterizează
starea maşinii şi refacerea acestora la sfârşitul programului de
întrerupere.

3 SUPERCALCULATOARE ŞI MICROPROCESOARE

3.1 Supercalculatoare

Problemele depăşirii capacităţii de calcul generate de volumul mare al


operaţiilor aritmetice din cadrul unor discipline de studiu (meteorologie,

62
dinamica fluidelor, aerodinamică, analiza structurilor, microelectronică,
fizica particulelor, chimia moleculară, matematici aplicate, simularea
numerică a sistemelor, prelucrarea imaginilor etc.) necesită creşterea vitezei
de execuţie a unităţii centrale, sau distribuirea calculelor pe mai multe
procesoare care lucrează în paralel.
Dezvoltarea sistemelor de calcul vizează asigurarea creşterii
performanţelor şi miniaturizarea.
Supercalculatoarele supercomputers sunt acele sisteme de calcul cu
performanţe deosebite, destinate în special aplicaţiilor ştiinţifice şi tehnice
avansate, spre deosebire de modelele comune şi mai răspândite, în general
afectate aplicaţiilor care nu solicită calcule numerice foarte pronunţate.
La cealaltă extremitate a gamei de sisteme de calcul se situează
microcalculatoarele care au la bază microprocesoare, iar adiţional, pot să
conţină: coprocesoare matematice, memorii cache, funcţii diverse de
comunicare şi de intrare/ieşire.
Microcalculatoarele sunt fabricate în cantităţi mari şi oferă performanţe
deosebite şi la preţuri relative scăzute.
În contextul sistemelor de calcul, conceptul de paralelism semnifică
faptul că mai multe acţiuni se pot derula simultan, într-o manieră
concurenţială. De aceea, prin creşterea gradului de paralelism al maşinii de
calcul va creşte şi capacitatea sa de prelucrare, dar maşina devine mai
complexă şi mai dificil de programat. Deşi sistemele care conferă un grad
ridicat de paralelism sunt doar rareori exploatate într-un procentaj maxim,
totuşi majoritatea aplicaţiilor pot profita, chiar şi într-o mai mică măsură de
arhitectura paralelă a sistemului.

Evaluarea performanţelor sistemelor de calcul


Sistemele de calcul sunt clasificate în funcţie de capacitatea de memorare
şi performanţele de calcul. Evaluarea capacităţii se realizează prin
contorizarea numărului de cuvinte de memorie în megaocteţi, gigaocteţi etc.
Evaluarea performanţelor de calcul este mai complexă, şi este condiţionată,
din punctul de vedere al utilizatorului de timpul de execuţie a programelor.
Pentru evaluarea performanţelor sistemelor de calcul sunt elaborate
programe de test benchmarks, dar nu se poate asigura standardizarea lor.
Totuşi, s-a realizat o regrupare a constructorilor de sisteme de calcul numită
SPEC System Performance Evaluation Cooperative cu scopul de a defini măsuri
standard de evaluare, concretizate în elaborarea un număr de aproximativ zece
programe de test scrise în limbajele de programare Fortran şi C.
Evaluarea propriu-zisă se realizează prin raportarea timpilor de execuţie
a programelor pentru diverse tipuri de maşini la timpul de referinţă (timp de

63
execuţie pe un sistem VAX11/780), obţinându-se un SPEC_ratio pentru
fiecare program, iar media aritmetică a tuturor acestor valori se exprimă
printr-un SPEC_mark.
Pentru procesoare se utilizează următoarele unităţi de măsură standard:
- MIPS: milioane instrucţiuni pe secundă;
- FLOPS: caracterizează reprezentarea în virgulă mobilă a
informaţiilor. Se utilizează MFLOPS (MegaFlops), GFLOPS
(GigaFlops), TFLOPS (TeraFlops);
- SPEC.
Aceste măsurători furnizează indicatori mai mult teoretici, alegerea unui
sistem de calcul se face în realitate în funcţie de gradul de satisfacere al
necesităţilor aplicaţiilor destinate.

Exemple de supercalculatoare
Se pot distinge două categorii de supercalculatoare:
- supercalculatoare vectoriale: procesorul este capabil să lucreze
asupra vectorilor de date;
- supercalculatoare multiprocesoare.
Cei mai reprezentativi constructori de supercalculatoare vectoriale sunt:
Cray în SUA, Fujitsu, Hitachi şi Nec în Japonia.
Primul supercalculator vectorial a fost Cray-1 (monoprocesor de 10
MIPS şi 160 MFLOPS) realizat în 1976 de Seymour Cray. În 1980 s-au
comercializat Cray-XMP şi Cray-2 având până la patru procesoare, fiecare
procesor fiind capabil de câte 25 MIPS şi 450 MFLOPS. Cray-3 şi seria
YMP confirmă tendinţa către microprocesoare, memorii centrale de mare
capacitate. La concurenţă cu Cray, NEC produce SX-3, care depăşeşte 25
GFLOPS cu cele patru procesoare ale sale.
Maşinile paralele care reprezintă singura direcţie de cercetare care
propune atingerea TFLOPS (mii de miliarde de operaţii în virgulă mobilă pe
secundă) sunt reprezentate de constructorii americani (TMC Thinking
Machine Corporation, Intel, Cray, IBM), japonezi (Fujitsu) şi cei europeni
(Kendall Square Research, Meiko, Telmat, ACRI, Archipel). De exemplu,
compania TMC lanseză CM-200 având 4000-64000 procesoare de 1 bit şi
CM-5 având 32-8000 procesoare pe 32 sau biţi.
Pipeling
Pipeling este tehnica care permite efectuarea mai multor activităţi în unitatea
de timp, atunci când trebuie repetată o operaţie asupra unui număr mare de
operanzi, prin segmentarea operaţiei complexe într-o secvenţă de acţiuni mai
simple, fiecare acţiune simplă fiind realizată de către un dispozitiv particular.

64
În acest context, în loc să fie concepută o unitate S, capabilă să efectueze
operaţia P într-un interval de timp T, se va diviza operaţia P în segmentele
P1, P2, P3, …, executate de către subunităţile S1, S2, S3, … în intervalele de
timp T1, T2, T3, …, fracţiuni ale timpului T.
Când lanţul pipeline este complet încărcat (plin), adică toate
subunităţile sunt ocupate, începe furnizarea rezultatelor într-un ritm mult mai
ridicat decât în cazul unei unităţi nesegmentate.
Prin utilizarea acestei tehnici nu creşte viteza de execuţie a unei operaţii,
doar se produc mai multe rezultate pe secundă, furnizând în mod continuu
operanzi la intrare pentru pipeling.
De axemplu, în cazul unei adunări în virgulă flotantă se poate segmenta
operaţia în cinci părţi corespunzând unui număr de cinci staţii de lucru,
afectate operaţiilor următoare:
- compararea exponenţilor;
- interschimbarea mantiselor (dacă este cazul);
- decalarea mantiselor;
- adunarea mantiselor;
- normalizarea rezultatului.
După cum se vede şi în figura următoare (A, B, C, D, E şi F sunt operaţii
de efectuat iar RA, RB, RC, RD, RE, RF, rezultatele acestor operaţii), debitul
rezultatelor este cam de n ori mai mare în cazul unei unităţi operaţionale
divizate în n părţi decât pentru o unitate nesegmentată.

FEDCBA S1 S2 S3 S4 S5 RFRERDRCRB RA

Secţiuni de
pipeling Rezultate RA RB RC RD RE RF

S5 A B C D E F
S4 A B C D E F
S3 A B C D E F
S2 A B C D E F
S1 A B C D E F
1 2 3 4 5 6 7 8 9 10 11 Timp
Tehnica pipeling se poate aplica şi altor dispozitive în afara celor de
calcul. De exemplu, secţiunea unităţii de comandă care tratează
instrucţiunile poate fi organizată în pipeling, segmentând ciclul de căutare şi
ciclul de execuţie a instrucţiunii într-o secvenţă de acţiuni, care se pot
reacoperi în timp, după cum urmează:

65
- căutarea în memoria centrală a instrucţiunii următoare;
- decodificarea codului operaţiei;
- căutarea operandului;
- activarea secvenţatorului;
- efectuarea operaţiei;
- incrementarea registrului CO cu o unitate.

Procesoare scalare şi vectoriale


Tehnica pipeling deschide calea prelucrării sistematice a blocurilor de date
numite şi vectori vectors. Un vector este o variabilă având mai multe valori.
Se numeşte procesor vectorial vector procesor o unitate de execuţie
(UAL) organizată pentru a efectua operaţii asupra vectorilor, operaţiile sunt
declanşate printr-o instrucţiune vectorială care face parte din setul de
instrucţiuni al maşinii.
Un procesor se numeşte scalar dacă el nu poate executa decât instrucţiuni
al căror efect se limitează la valorile scalare (care au o singură valoare).
Pentru a putea fi eficient, un procesor vectorial trebuie să dispună de
blocuri de registre ultra-rapide şi într-un număr suficient pentru a calcula şi
depune rezultatele intermediare din pipeling (adesea se procedează la
înlănţuirea pipeling-urilor).
Procesoarele superscalare sunt procesoare capabile să execute în
paralel un număr mic de instrucţiuni (2 – 5) (de exemplu: Alfa produs de
DEC sau IBM RS 6000), asigurând o simultaneitate reală a operaţiilor.
Performanţa maşinilor superscalare depinde mult de compilator, care trebuie
să fie capabil să găsească suficiente instrucţiuni ce se pot executa în paralel.
Abordarea VLIW Very Long Instruction Word constă în plasarea mai
multor instrucţiuni executabile într-un cuvânt de memorie suficient de mare
(peste 100 de biţi). Unul dintre primele microprocesoare care a utilizat această
tehnică este i860 al firmei Intel care are instrucţiuni de lungime 128 de biţi.

Maşini paralele
Progresul tehnologic permite astăzi realizarea unor arhitecturi cu un
foarte înalt nivel de paralelism, cu sute sau chiar mii de procesoare. Aceste
maşini sunt supercalculatoarele care, pentru anumite aplicaţii pot să ofere
posibilităţi de atingere a unor performanţe remarcabile.
Ideea care stă la baza oricărui calculator paralel este distribuirea
activităţilor necesare rezolvării unei probleme pe mai multe procesoare
făcând parte din aceeaşi maşină, deoarece majoritatea programelor se
rulează, de obicei în secvenţă, existând blocuri de instrucţiuni toatal
independente care ar putea fi executate simultan.

66
Aceasta presupune un nou stil de programare şi o complexitate deosebită la
nivel software. În acest context, anumite probleme, cum sunt cele din
matematicile aplicate, prelucrarea imaginilor sau fizică posedă un bun nivel de
paralelism natural şi pot fi adaptate uşor la prelucrarea paralelă.
În concluzie, există la ora actuală suficiente instrumente diferite şi destul
de complementare destinate rezolvării unor probleme complexe:
- maşini scalare puternice care execută instrucţiunile în secvenţă
potrivit principiilor lui von Neumann (în ultimii 45-50 de ani);
- procesoare vectoriale foarte puternice, capabile să rezolve
probleme dificil sau chiar imposibil de rezolvat cu procesoarele
scalare (în ultimii 20-25 de ani);
- maşini paralele cu enorma capacităţi de calcul distribuite pe un
număr mare de procesoare (în ultimii 10-15 ani).

3.2 Paralelism

Se poate face distincţie între mai multe forme de paralelism:


- paralelism intern, în interiorul unui calculator clasic, care se poate
prezenta sub trei forme:
- paralelism prin duplicare: se poate realiza o simultaneitate
reală a anumitor operaţii sau acţiuni prin multiplicarea
dispozitivelor afectate (de exemplu: sumatoare binare, bus-uri
multilinii pentru transferuri paralele, memorie pe bază de
blocuri independente întreţesute etc.);
- paralelism prin anticipare: se realizează creşterea
performanţelor prin efectuarea unor acţiuni susceptibile să
reducă timpul de aşteptare al unei unităţi critice (de exemplu:
reacoperirea acţiunilor în pipeling, dotarea CPU cu
antememorie, transfer de date între periferic şi memorie în
vederea prelucrării ulterioare etc.);
- paralelism prin multiplexare: mai multe unităţi lente sunt
deservite de către o unitate rapidă, situaţie în care se realizează
o simultaneitate aparentă (de exemplu: sistemele utilizate în
timp partajat time sharing).
- paralelism extern, care presupune utilizarea mai multor procesoare
între care există o anumită interdependenţă. Clasificarea lui Flinn
cu privire la evoluţia paralelismului extern evidenţiază arhitecturile:
- SISD Single Instruction Single Data stream: este maşina von
Neumann strict secvenţială şi care nu este prevăzută cu
paralelism extern. A posedă o singură unitate de comandă care

67
tratează o singură secvenţă de instrucţiuni Single Instruction
stream şi o singură unitate de execuţie (UAL) care tratează o
singură secvenţă de date Single Data tream;
- SIMD Single Instruction Multiple Data streams: sunt maşini
care posedă o unitate de comandă unică dar mai multe unităţi
de execuţie. Toate procesoarele execută aceeaşi instrucţiune
simultan. În această categorie se pot clasa procesoarele
vectoriale care execută aceeaşi instrucţiune asupra tablourilor
de elemente;
- MIMD Multiple Instructions Multiple Data streams: se pot
clasa în acestă categorie multiprocesoarele, unde fiecare
procesor execută un program diferit şi de asemenea, maşinile
paralele în care toate procesoarele lucrează asupra unei singure
probleme;
- MISD Multiple Instructions Single Data stream: s-a prevăzut
o asemenea rhitectură din motive de simetrie, dar nu s-a
realizat nici-un exemplar din aceasta categorie.
Se poate remarca faptul că majoritatea tehnicilor care vizează creşterea
performanţelor (de exemplu: pipeling, antememorie etc.) nu se adresează în
mod direct unui utilizator concret (paralelism transparent).
Există de asemenea paralelism vizibil, care necesită colaborarea
utilizatorului (de exemplu: maşini vectoriale şi paralele).

3.3 Microprocesoare

Un microprocesor este un circuit integrat care realizează o unitate de


prelucrare completă (unitate de comandă + UAL).
Un microcalculator este un ansamblu microprocesor + memorie +
intrări / ieşiri + echipamente periferice.
Cei doi mari constructori: Intel şi Motorola au asigurat o evoluţie
asemănătoare pentru microprocesoarele clasice.
Prin comparaţie cu marile sisteme de calcul, microcalculatoarele oferă
următoarele caracteristici generale:
- aplicarea strictă a principiului arhitectural von Neumann;
- viteză de calcul comparabilă;
- memorii de capacitate mai redusă;
- dispozitive de intrare / ieşire şi periferice mai puţin performante.
Un microcalculator conţine următoarele elemente componente:
- microprocesor, care este CPU-ul său;

68
- memoria, care poate fi de tip RAM, pentru înregistrarea datelor,
rezultatelor intermediare şi finale sau de tip ROM, unde sunt
înregistrate instrucţiuni, constante, rutine de bibliotecă etc.;
- intrările/ieşirile care conţin registre tampon şi circuite de interfaţă
care permit unităţilor periferice să comunice cu sistemul;
- bus-ul de date permite transferul informaţiilor în cele două sensuri.
Într-un microcalculator pe 8, 16, 32, 64, 128 biţi bus-ul va avea 8,
16, 32, 64, 128 linii;
- bus-ul de adrese este unidirecţional, el procesorul pentru adresarea
memoriilor şi a registrelor tampon de interfaţă cu perifericele
(exemplu: un bus de adrese cu 16 linii poate transporta 2 16 = 65536
adrese diferite);
- bus-ul de comenzi transportă semnalele utilizate pentru a
sincroniza diversele activităţi care se desfăşoară în unitatea
funcţională a microcalculatorului (exemplu: semnale se ceas intern,
semnale de citire, semnale de scriere, semnale de întrerupere etc.).

Calculator personal şi staţie de lucru


Pentru configurarea unui microcalculator în calculator personal este
suficientă adăugarea unor unităţi periferice adaptate interacţiunii om-maşină
(de exemplu: o tastatură, un ecran de vizualizare, o imprimantă, un mouse etc.).
Constructorii oferă de asemenea o largă gamă de memorii auxiliare pentru
stocarea fişierelor: hard-discuri magnetice sau optice, cititoare de discuri etc.
Trecerea de la calculator personal la calculator profesional sau staţie
de lucru work-station necesită un CPU mai rapid, memorie de mare
capacitate, ecran grafic color sofisticat şi produse software corespunzătoare.
Microcalculatoarele cunosc la ora actuală un mare succes ca staţii de
lucru sau calculatoare personale deoarece sunt maşini polivalente suficient
de puternice pentru rezolvarea problemelor curente, care posedă produse
software de tip editoare de texte, tabelatoare, sisteme de gestiune de baze de
date etc. Legarea în reţea a unor astfel de maşini de calcul facilitează
partajarea datelor între mai mulţi utilizatori concurenţi.
Microcalculatorul care a revoluţionat lumea informatică este cel
conceput şi dezvoltat de firma IBM, numit Personal Computer sau amai
simplu IBM PC care a apărut în 1981.
Datorită succesului repurtat de această maşină, s-au realizat maşini
similare identificate ca PC compatibile IBM, sau mai simplu PC.
Toate aceste calculatoare PC se bazează pe microprocesoare Intel. Până
la sfârşitul anilor ’80 sistemul de operare al acestor maşini este DOS Disk
Operating System realizat de firma Microsoft. Acesta este un sistem de

69
operare simplu, bazat pe o interfaţă de tip text şi a cărui utilizare solicită
cunoaşterea unui limbaj informatic specific.
La sfârşitul anilor ’80 a apărut un nou sistem de operare, Windows,
bazat pe o interfaţă utilizator-grafică mult mai prietenoasă, similară cu cea a
calculatoarelor Macintosh ale firmei Apple.
Interfaţa utilizator-grafică GUI: Graphical User Interface utilizează
ferestre, meniuri, pictograme şi privilegiază utilizarea mouse-ului.
În timp ce staţiile de lucru au o „vocaţie” mai ştiinţifică, calculatoarele
Macintash şi PC se adresează publicului larg.
Tendinţa actuală în domeniul microcalculatoarelor este aceea de realizare a
maşinilor multimedia, care oferă posibilitatea prelucrării unor tipuri diferite
de informaţii (de exemplu: date, sunet, imagini fixe sau animate).
Cei mai reprezentativi constructori de pe piaţa staţiilor de lucru sunt: Sun
Microsystems, IBM, HP, DEC.
Cu un sistem de operare bazat pe UNIX, adesea conectate în reţea în
configuraţii numite clusteri de staţii de lucru, aceste staţii de lucru pot
realiza capacităţi de calcul mari şi pot fi utilizate în paralel, de o manieră
asemănătoare supercalculatoarelor, dar la un preţ mult mai atrăgător.
Calculatoarele portabile care manifestă la ora actuală o adevărată
expansiune sunt caracterizate prin dimensiuni reduse, greutate de câteva
kilograme, autonomie de funcţionare de câteva ore şi pot fi echipate cu hard-
discuri, ecrane color, fax, imprimante miniaturale etc.
În domeniul calculatoarelor portabile există două tendinţe:
- calculatoare cu tastatură notebook care sunt microcalculatoare
clasice care beneficiază de noile tehnologii în privinţa ecranului (de
exemplu: cristale lichide etc.);
- calculatoare fără tastatură block-notes sau notepads, care
posedă un ecran tactil asupra căruia se poate scrie cu un creion
special şi un program de recunoaştere a caracterelor scrise.

4 ELEMENTE DE TELEINFORMATICĂ

Teleinformatica (telematica) se poate defini ca fiind domeniul


informaticii care utilizează mijloace de transmisie la distanţă a informaţiilor.

70
Reţelele de calculatoare sunt constituite din elemente ale informaticii şi
ale sistemelor de telecomunicaţii.
Evoluţia teleinformaticii a cunoscut mai multe etape:
a) transmiterea datelor între două calculatoare (anii ‘60);
b) accesarea informaţiei la distanţă, deci o tendinţă de descentralizare
prin utilizarea staţiilor de intrare/ieşire (anii ‘70);
c) reţele de terminale (comutare de circuite cu concentratori,
multiplexare), reţele de calculatoare (comutare mesaje, pachete)
(sfârşitul anilor ‘70);
d) teleinformatica cu utilizarea pe scară largă a reţelelor publice, locale,
comunicaţie între reţele prin tehnica sateliţilor, utilizarea fibrelor
optice ca suport fizic, comunicaţia digitală etc. (anii ‘80 şi în prezent).
În general, o reţea poate fi definită ca o mulţime de noduri legate printr-
un ansamblu de drumuri (deci poate fi reprezentată printr-un graf).
Topologia reţelei vizează localizarea nodurilor şi modul lor de înlănţuire.
În mod obişnuit se utilizează un număr de reţele, ca de exemplu: şosele, căi
ferate, linii aeriene, poşta, telefon, electricitate, apă, radio, televiziune etc.
Noţiunea de reţea nu este un concept nou şi exemplele anterioare permit
evidenţierea unor caracteristici generale ale reţelelor:
a) serviciul oferit prin reţea depinde de tipul legăturii folosite în reţea.
De exemplu, şoselele furnizează o reţea punct la punct, în timp ce
apa este difuzată în toate nodurile reţelei;
b) utilizarea unei reţele în bune condiţiuni implică respectarea unui
anumit număr de reguli. De exemplu, pe şosele se poate circula
respectând regulile de circulaţie;
c) o reţea se poate construi pe alte reţele. De exemplu, poşta utilizează
şosele, căi ferate, linii aeriene.
O reţea teleinformatică (o vom numi, fără riscul confuziei, reţea) este o
reţea ale cărei noduri sunt constituite din unităţi de prelucrare a informaţiei,
schimbul de informaţie realizându-se prin intermediul legăturilor dintre
noduri, numite canale de transmisie.
În practică, nodurile pot fi calculatoare sau echipamente terminale (ecran
de vizualizare + tastatură + imprimantă) şi canalele de transmisie sunt adesea
linii telefonice pentru marile reţele şi cabluri coaxiale pentru reţelele locale.
Pentru schimbul de informaţie, două unităţi de prelucrare trebuie să
respecte aceleaşi protocoale, care sunt reguli complexe de comunicare.
4.1 Transmisia informaţiilor

Suporturi fizice ale unei căi de transmisie


Căile de transmisie se bazează pe propagarea undelor electromagnetice:

71
a) cale metalică: este o linie electrică ce poate fi o linie telefonică sau
un cablu electric. Această soluţie prezintă unele inconveniente care
se referă la sensibilitatea la zgomote, scăderea semnalului transmis
la distanţă etc;
b) fascicol hertzian: utilizează unde radioelectrice pentru transportul
informaţiei;
c) fibre optice: transportul informaţiei este realizat prin propagarea
undelor luminoase în fibre de sticlă, prezenţa sau absenţa unui
semnal luminos permiţând codificarea unui bit de informaţie.
Utilizarea acestor diverse suporturi de informaţie poate fi schematizată
astfel: o legătură intercontinentală este realizată cu ajutorul unui satelit, o
legătură între calculatoarele unei ţări se realizează prin linii telefonice, o
legătură între două clădiri din acelaşi oraş se face prin fibre optice, legătura
între diverse echipamente din aceeşi clădire utilizează cablu coaxial, iar dacă
echipamentele sunt apropiate, se foloseşte un simplu cablu electric.

Moduri de transmisie a informaţiei


a) transmisie paralelă: se transmit mai mulţi biţi simultan, de
exemplu, bus-ul unui microcalculator transmite 8 sau 16 biţi
simultan, o linie telefonică de lungă distanţă poate asigura 12
comunicaţii simultane etc.;
b) transmisie serială: informaţiile se transmit pe aceeaşi linie şi se
succed în timp.
Sincronizarea transmisiei informaţiei
Orice transfer de informaţie care utilizează telecomunicaţiile este în
general realizat sub formă serială. Una din principalele probleme ale
transmisiei seriale constă în sincronizarea emiţătorului cu receptorul
informaţiei. Transmisia paralelă ridică probleme de sincronizare şi mai mari
şi nu se utilizează decât pe distanţe scurte. Majoritatea echipamentelor
informatice sunt dotate cu o ieşire (poartă) RS232C, care este ieşire standard
permiţând o transmisie serială. Sincronizarea determină eşantioane ale
semnalului transmis pentru a recunoaşte biţii constituind informaţia. O
secvenţă de biţi corespunde unui şir de schimbări ale stării semnalului,
fiecare stare durează un interval foarte scurt de timp. Receptorul trebuie să
fie sincronizat pentru ca începutul şi sfârşitul eşantioanelor să corespundă
schimbărilor de stare (sincronizare bit). Când receptorul primeşte biţii de
informaţie ele trebuie să reconstituie semnalul, deci să reconstituie
caracterele (sincronizare caracter). Se disting două moduri de transmisie:
a) transmisia asincronă: caracterele sunt emise în mod neregulat, ca
de exemplu caracterele tastate. Sincronizarea între emiţător şi

72
receptor se realizează în timpul transmiterii fiecărui caracter.
Datorită transmisiei aleatoare a caracterelor, acestea sunt încadrate
de biţi suplimentari pentru asigurarea corectitudinii transmisiei
(start-bit, stop-bit, bit de paritate). Acest mod de transmisie este
relativ simplu şi ieftin, dar redondanţa datorată biţilor adăugaţi nu
permite realizarea unei mari capacităţi de transmisie şi utilizarea sa
este limitată la terminale lente ca tastatura sau imprimanta;
b) transmisia sincronă: biţii sunt emişi în mod regulat, fără separare între
caractere. Pentru sincronizare se utilizează un ceas-bit atât de către
emiţător cât şi de către receptor. Sincronizarea caracterelor se realizează
prin recunoaşterea secvenţelor particulare de biţi. Acest mod de transmisie
permite debite mai mari de informaţie (superioare de 12000 biţi/sec).

Moduri de exploatare a unei căi de transmisie


a) simplex: transmisia este unidirecţională, o extremitate emite iar
cealaltă recepţionează. Difuziunile radio şi TV sunt exemplele cele
mai caracteristice;
b) semiduplex half-duplex (bidirecţional alternat): permite o
transmisie în două sensuri, dar alternativ, fiecare din cele două
extremităţi primeşte şi emite la rândul său, dar niciodată simultan;
c) duplex full-duplex (bidirecţional simultan): permite o transmisie
simultană în cele două sensuri.

Banda de trecere
O cale de transmisie nu permite decât transportul semnalelor care aparţin
unui anumit domeniu (bandă) de frecvenţe. Banda de frecvenţe corect
transmisă este numită bandă de trecere (notată W), şi constituie
caracteristica esenţială care determină direct capacitatea de transmisie.
H. Nyquist a arătat că rapiditatea de semnalizare (capacitatea de
transmisie) a unei căi este C = 2*W bound, unde W este mărimea benzii de
trecere. Bound-ul este unitatea de rapiditate a semnalizării şi corespunde
unui anumit număr de semnale pe secundă, iar dacă fiecare semnal permite
transmiterea a n biţi, atunci C = 2*n*W biţi/sec (bps).
În anul 1948, C. Shannon a arătat că rapiditatea de semnalizare este
determinată nu numai de banda de trecere ci şi de raportul semnal (S) /
bruiaj (B), şi anume: C = W * log2 (1 + S / B) (Hz).
Transmisie analogică şi digitală
a) transmisia analogică: constă în a utiliza un semnal simplu numit
undă purtătoare căreia i se modifică unul sau mai mulţi parametri:
amplitudine, frecvenţă, fază;

73
b) modularea: constă în transformarea informaţiilor digitale în
informaţii analogice prin modelarea unei unde purtătoare
sinusoidală periodică ce se poate reprezenta s (t) =A*sin (*t+),
sau s(t)=A*sin (2**f*t+) unde: A este amplitudinea semnalului, 
este pulsaţia, f este frecvenţa, iar  este faza inţială. Există trei
posibilităţi de modulare a semnalului:
 modulare în amplitudine: s (t) = A (t) * sin ( * t + );
 modulare în frecvenţă: s (t) = A * sin (2 *  * f (t) * t+);
 modulare de fază: s (t) = A * sin (2 *  * f * t +  (t)).

Transmisia digitală şi modularea


Transmisia digitală sau numerică constă în a transmite biţii sub formă de
impulsuri electrice pătrate având o durată şi o amplitudine pătrate.
Codificarea informaţiilor se realizează în mod asemănător cu cea
utilizată pentru memorare pe un suport magnetic. Transmisia digitală
necesită o bandă de trecere largă. Noile tehnologii bazate pe fibre optice
permit transmisii digitale.
Pentru transmisia informaţiilor analogice este necesară efectuarea unei
modulări care constă în eşantionarea semnalului analogic la emisie,
transmisia eşantioanelor sub formă digitală şi reconstituirea semnalului la
recepţie. Un rafinament al acestei tehnici, modularea delta, constă în
transmiterea diferenţelor între două eşantioane în locul acestora.

Multiplexare
Multiplexarea înseamnă partajarea unei căi de transmisie între mai multe
legături. O legătură este stabilirea unei comunicaţii între două echipamente
informatice. Sunt utilizate în principal două tehnici:
a) multiplexare frecvenţială FDM: Frequency Division
Multiplexing (spaţială) care constă în divizarea benzii de trecere a
căii de transmisie, semnalele sub-benzilor de trecere sunt adăugate
unele altora pentru a fi transmise pe calea de transmisie cu ajutorul
multiplexorului, iar la recepţie un demultiplexor filtrează semnalul
primit. Semnalele transmise astfel sunt analogice, pentru semnalele
numerice trebuie utilizat un modem pentru modularea acestora;
b) multiplexarea temporală: TDM: Time Division Multiplexing
constă în partajarea în timp a căii de transmisie între mai multe
transmisii, tehnică ce se poate utiliza şi pentru transmisii digitale.
Multiplexoarele inteligente ITDM: Intelligent TDM sau statistice
rezolvă problema alocării tranşelor de timp potrivit necesităţilor
fiecărei legături (mod asincron) (se mai numesc concentratoare).

74
3.2 Reţele de calculatoare

O reţea de calculatoare network este o mulţime de calculatoare (şi


echipamente terminale), geografic dipersate, conectate între ele prin una sau
mai multe legături pentru a permite schimburi de informaţii.
Calculatoarele unei reţele pot să aparţină unor categorii diverse, de la
supercalculatoare până de la microcalculatoare care evident, pot fi de tipuri
diferite. Dacă sistemele de calcul ale reţelei sunt compatibile între ele
reţeaua este omogenă, altfel reţeaua este neomogenă.
O reţea are drept scop de a oferi un anumit număr de servicii
utilizatorilor, bazate pe schimbul informaţiilor (acces la distanţă):
- acces la informaţii (programe, date) stocate pe alte calculatoare ale reţelei;
- acces la alte calculatoare (de exemplu un supercalculator);
- permite schimbul de informaţii între utilizatori (mesagerie);
În funcţie de „diametrul” reţelei, adică depărtarea maximă între noduri,
există următoarea clasificare a reţelelor:
a) reţea extinsă WAN: Wide Area Network: reţea ale cărei noduri
sunt geografic foarte îndepărtate unele de altele (mai multe sute, sau
chiar mii de kilometri). Acest tip de reţea utilizează în general
reţelele publice (de exemplu, linii telefonice);
b) reţea metropolitană MAN: Metropolitan Area Network: reţea ale
cărei noduri se situează în aceeaşi metropolă. Fibrele optice sunt
adesea utilizate pentru realizarea unei asemenea reţele;
c) reţea locală LAN: Local Area Network: reţea ale cărei noduri se
găsesc în aceeaşi clădire sau în clădiri vecine, deci depărtate până la
câteva sute de metri.
Erorile de transmisie a informaţiilor în reţea constituie o problemă
importantă. Există metode de detectare a erorilor, iar estimarea posibilităţii
de apariţie a erorilor este exprimată astfel:
 1 bit eronat din 1012 în reţelele locale;
 1 bit eronat din 105 în reţelele extinse.

Reţelele punct la punct şi reţelele de difuziune


Pentru a permite schimbul de informaţii între doi utilizatori este necesar
să se poată adresa membrii reţelei. O tehnică constă în a adăuga fiecărui
mesaj adresa destinatarului, într-o manieră analoagă corespondenţei poştale.
Deoarece destinatarul nu este în mod obligatoriu legat direct cu expeditorul,
mesajul va tranzita prin nodurile intermediare care decodifică adresa şi care

75
transmit în continuare mesajul la un nod apropiat, într-o bună direcţie.
Aceasta este o reţea punct la punct.
O altă tehnică de transmisie la distanţă utilizează o reţea de difuziune
broadcasting, care difuzează direct informaţia către toţi membrii reţelei.
Mesajul este întotdeauna etichetat cu o adresă pe care numai destinatarul o
recunoaşte. Acest tip de reţea necesită în mod normal utilizarea unui satelit
pentru transmisia informaţiilor.

Tehnici de comutaţie a datelor


În general, drumul urmat de informaţie de la expeditor la destinatar,
parcurge un anumit număr de noduri intermediare care trebuie să asigure
respectarea corectitudinii datelor pe care le primesc. Există mai multe
metode care permit efectuarea comutaţiilor necesare fiecărui nod:
a) comutaţia de circuite circuit switching: se stabileşte o conexiune
fizică temporară între nodurile implicate în schimbul de informaţie.
Transferul are loc din momentul stabilirii conexiunii care rămâne
activă pe tot parcursul comunicaţiei, chiar şi în perioadele când nu
are loc nici-un schimb de informaţie. Acest tip de comutaţie este
rentabil pentru o linie care suportă puţine schimburi de informaţie,
exemplul cel mai sugestiv fiind cel al unei reţele telefonice.
b) comutaţia de mesaje message switching: cu această tehnică se trimite un
mesaj cu adresa sa în reţea. Când mesajul soseşte la un nod, acesta
decodifică adresa şi-l trimite nodului următor, în direcţia destinatarului,
conform tabelei de rutare. Mărimea mesajelor poate fi variabilă, ceea ce
impune nodurilor să dispună de mijloace de stocare a mesajelor. Acest tip
de comutaţie este mai suplu decât cel precedent deoarece permite
înregistrarea mesajului dacă nodul receptor nu este disponibil.
c) comutaţia de pachete packet switching: este similară cu comutaţia de
mesaje, dar limitează mărimea informaţiilor transmise. Se procedează la
divizarea mesajului de transmis în pachete de mărime limitată (de exemplu
1024 biţi = 128 octeţi) şi se trimit separat pachetele în reţea. Datorită
mărimii reduse, pachetele sunt mai puţin sensibile la erori, mai uşor de
stocat (memoria centrală). Printr-o numerotare corespunzătoare a
pachetelor se poate reconstitui mesajul la destinaţie.

Topologia reţelelor de calculatoare


În figura următoare sunt prezentate diverse topologii de reţea:

76
Reţea de tip plasă Reţea de tip stea Reţea de tip arbore

Reţea de tip inel Reţea de tip bus

Reţeaua de tip plasă este caracterizată prin faptul că două noduri


oarecare sunt legate între ele. Acest tip de reţea asigură o mare supleţe şi
siguranţă în utilizare, dar este dificil de realizat pentru un număr foarte mare
de noduri. În general plasa nu este perfectă (sunt anumite noduri nelegate),
situaţie în care se vorbeşte despre reţea plasă parţială. Toate celelalte tipuri
de reţele sunt particularizări ale reţelei de tip plasă, obţinute prin impunerea
unor restricţii asupra legăturilor între noduri.
a) Reţeaua de tip stea este o reţea centralizată, un singur nod este
legat direct la toate celelalte, fără ca acestea să aibă legături între
ele. Nodul central suportă orice sarcină a reţelei.
b) Reţeaua de tip arbore este o reţea ierarhică repartizată pe mai multe
nivele, nodurile aceluiaşi nivel nu sunt legate între ele dar sunt legate
la un nod de nivel superior (reţeaua telefonică este un bun exemplu).
c) Reţeaua de tip buclă sau inel este o reţea în care fiecare nod este
legat la două noduri pentru a forma un inel. Este o reţea
descentralizată de tip punct la punct.
d) Reţeaua de tip bus este o reţea de difuzine, în care toate nodurile
sunt conectate pe acelaşi suport.
Suportul fizic de transmisie cel mai utilizat în reţelele locale este cablul
coaxial.
Reţelele extinse au în general o topologie obţinută pornind de la o
combinaţie de trei topologii: reţea parţială de tip plasă, reţea de tip stea şi
reţea de tip arbore.

77
Topologiile cele mai utilizate pentru reţelele locale sunt cele de tip bus şi inel.
Reţelele locale funcţionează în general prin difuziune, adică o staţie ce
doreşte să transmită un mesaj îl expediază în reţea, staţia vizată prin mesaj
recunoaşte adresa sa şi în consecinţă ea tratează acest mesaj, în timp ce alte
staţii, nerecunoscând mesajul, îl ignoră.

Protocoale de reţea
Un protocol de reţea este constituit din mulţimea regulilor care trebuie
să fie respectate pentru a realiza un schimb de informaţii între sistemele de
calcul din cadrul reţelei.
O modalitate de simplificare a problemei comunicării în reţea este
aceea de divizare a acesteia prin definirea mai multor nivele de comunicare
şi stabilind un protocol pentru fiecare nivel.
Problema standardizării presupune definirea de norme pentru
simplificarea comunicaţiilor în reţelele eterogene.
În timp ce constructorii au tendinţa de a defini propriile lor protocoale,
totuşi, un anumit număr de instituţii şi organizaţii internaţionale încearcă să
definească standarde, şi anume:
 departamentul apărării americane DOD a definit protocolul
TCP/IP pentru reţeaua Arpanet;
 instituţiile internaţionale:
- CCITT Comité Consultatif International du Téléphone et du
Télégraphe a definit recomandări reunite sub denumirea de seria
V (transmisia datelor prin telefon) şi seria X (reţele publice);
- ISO International Standards Organization cu modelul OSI
Open Systems Interconnection;

Modelul ISO - OSI


Modelul OSI Open Systems Interconnection, elaborat de organizaţia
ISO International Standards Organization între anii 1975-1985, trebuie să
permită interconectarea sistemelor de calcul de tipuri diferite.
Interesul acestui model este acela de a diviza mulţimea protocoalelor de
reţea în şapte nivele, între care sunt definite două tipuri de relaţii:
 verticale, între nivelele aceluiaşi sistem (se numesc interfeţe);
 orizontale, relative la dialogul la acelaşi nivel între sisteme diferite
(protocoale care definesc reguli de schimb).
Fiecare nivel furnizează nivelului superior un anumit număr de informaţii
cunoscute sub denumirea de primitive.
Vom prezenta în continuare o descriere succintă a celor şapte nivele ale
modelului ISO-OSI:

78
a) Nivelul 1 (fizic) este cel mai de jos nivel şi descrie caracteristicile
electrice şi echipamentul fizic de transmisie (cabluri, fascicole
hertziene etc.). El se ocupă de conexiunea fizică a staţiei la reţea,
permite transmisia de biţi între două sisteme, defineşte dacă
transmisia este sincronă sau asincronă, rezolvă probleme de
modulare/demodulare ale informaţiilor.
b) Nivelul al 2-lea (legătură de date, sau linie) data link are drept
scop transmisia datelor structurate în pachete de biţi fără erori (în
caz de eroare se procedează la retransmisia acestora).
c) Nivelul al 3-lea (reţea) serveşte în principal asigurării comutaţiei şi
rutării pachetelor de date între nodurile reţelei, de asemenea
efectuează controlul fluxului informaţiilor.
d) Nivelul al 4-lea (transport) permite stabilirea, întreţinerea şi
întreruperea conexiunilor de transport. Se efectuează controlul
fluxului informaţiilor şi se asigură segmentarea şi reasamblarea
mesajelor, precum şi multiplexarea căilor de tramsmisie.
e) Nivelul al 5-lea (sesiune) permite stabilirea unei conexiuni logice
între două aplicaţii, asigură organizarea şi sincronizarea dialogului,
modul de transmisie: simplex, semiduplex, duplex.
f) Nivelul al 6-lea (prezentare) se ocupă de aspectele prezentării
(sintaxa) datelor, conversia codului, formatul datelor, optimizarea
transferului prin diverse metode de comprimare şi asigurarea
securităţii datelor prin criptare.
g) Nivelul al 7-lea (aplicaţie) furnizează servicii şi interfeţe de
comunicaţie ale utilizatorului, deci constituie mulţimea punctelor de
intrare în programele utilizatorilor.

Conexiuni între reţele


Reţele, sau anumite părţi ale reţelelor locale pot fi legate, utilizând:
a) repetor repeater: ce permite conectarea a două reţele la nivelul
fizic, lucrează deci la nivelul 1 OSI şi are drept scop unic
transmiterea de biţi de la o reţea la alta;
b) pod bridge: lucrează la nivelul al 2-lea OSI şi asigură trasmiterea
fizică a informaţiilor sub formă de pachete, garantând absenţa erorilor;
c) rutor router: lucrează la nivelul al 3-lea OSI şi asigură rutarea
pachetelor între diferite reţele;
d) pasarelă gateway: lucrează în general la nivelul al 7-lea OSI şi
leagă două reţele oricare ar fi natura lor, ocupându-se de toate
conversiile necesare.

79
Conexiuni inter-reţele: internet şi TCP/IP
Pentru a încerca rezolvarea conexiunii între diferite reţele a apărut
noţiunea de internetwork sau general referită internet. Internet defineşte o
mulţime de protocoale independente de reţea. O versiune UNIX a acestor
protocoale a fost dezvoltată în ultima perioadă şi a avut ca efect conexiunea
unui mare număr de universităţi, firme şi persoane fizice.
Un anumit număr de aplicaţii sunt bazate pe protocoale TCP/IP de înalt
nivel şi pot fi considerate ca servicii universale:
 poşta electronică;
 transfer de fişiere la distanţă;
 emularea unui terminal la distanţă;
 gestiunea automată a reţelelor.
Adresarea staţiilor într-o reţea internet se realizează printr-o adresă pe 32
biţi descompusă în două părţi (identificatorul reţelei şi identificatorul local al
staţiei) şi reprezentată în general prin patru numere de câte 8 biţi.

Conceptul client - server


O utilizare importantă a reţelelor este cooperarea între aplicaţii.
Conceptul de bază utilizat pentru cooperare este acela de client - server,
care este folosit ca model de bază pentru aplicaţiile distribuite.
Termenul server se aplică oricărui program care oferă un serviciu care
poate fi extins de-a lungul reţelei. Un server primeşte cereri, le tratează şi le
retrimite celui care le-a solicitat (client).
Termenul client se aplică oricărui program care trimite o cerere unui
server şi aşteaptă rezultatele.

Evoluţia reţelelor de calculatoare


În situaţia actuală, reţelele de telecomunicaţii existente permit transportul
unei mari varietăţi de informaţii sub forme diverse, ca de exemplu: cuvinte
(telefon), mesaje (telex), imagini (telecopiator, televiziune), ca şi date
informatice. Pentru a se putea transporta toate aceste tipuri de informaţii au fost
realizate: reţea telefonică, reţea telex, diverse reţele specializate permiţând
schimbul de informaţii între sistemele de calcul. Cea mai importantă este
reţeaua telefonică bazată pe transmisia semnalelor analogice.
Reţelele viitorului se bazează pe transmisii numerice, cu cabluri coaxiale,
fibre optice şi sateliţi pentru a transmite date, imagini şi conversaţii telefonice.
a) RNIS (reţea numerică de servicii integrate) IDSN, este
implementată în cea mai mare parte a ţărilor europene şi SUA.
Legăturile internaţionale ridică însă unele probleme datorită

80
particularităţilor de implementare a reţelelor specifice fiecărei ţări.
Această reţea oferă servicii deosebite:
 servicii suport de informaţii (transmisie date + servicii
telefonice);
 servicii complementare (identificare apel, sub-adresare
terminale, portabilitate etc);
 teleservicii (transmisii de fişiere cu imagini fixe sau animate,
videofonia, videoconferinţa etc);
b) Evoluţia comutaţiei prin pachete vizează următoarele aspecte esenţiale:
 creşterea performanţelor prin sporirea debitului şi simplificarea
protocoalelor de reţea;
 posibilitatea transmisiei izocrone (vocea);
c) Releu de cadre frame relay: este o simplificare a transmisiei prin
pachete. În acest caz se utilizează acelaşi protocol de rutare, dar se
suprimă protocoalele de control a erorilor şi a fluxului (nivelul reţea
este vid). Această abordare este de 4-10 ori mai rapidă decât
comutaţia prin pachete şi se dovedeşte bine adaptată pentru
interconexiunea reţelelor locale.
d) Releu de celule cell relay are drept principiu descompunerea
informaţiilor în mici pachete de lungime fixă şi determinarea rutei
acestora. Comutaţia prin circuite permite transportul informaţiilor
izocrone (vocea), în timp ce comutaţia prin pachete este mai
adaptată transmisiei informaţiilor numerice. Releul de celule
realizează deci un compromis între cele două moduri de comutaţie.
e) RNIS cu bandă largă: permite transportul tuturor tipurilor de informaţii
(de exemplu, imaginile de televiziune). Spre deosebire de RNIS prima
versiune, care nu solicită modificarea cablajului abonaţilor, RNIS cu
bandă largă cere modificări multiple în reţeaua de transport şi va utiliza în
acest sens tehnica sateliţilor şi fibrele optice, mod de transfer asincron
potrivit tehnicii ATM Asynchronous Transfer Mode.
f) Reţele locale fără fir CLAN: Cordless LAN: nu necesită cablare, se
utilizează doar în cazuri particulare datorită tehnologiei foarte costisitoare.
Transmisia se realizează prin unde radio sau prin infraroşu.
g) Reţele de foarte înalt debit: dezvoltă viteze de transfer de ordinul
gigabiţilor pe secundă prin utilizarea fibrelor optice. Încă nu s-au definit
protocoale standard ci doar particulare care realizează conexiuni punct la
punct şi care necesită echipamente specifice foarte perfecţionate.
5 ELABORAREA PROGRAMELOR

81
Tehnologia produselor software software engineering caracterizează
mulţimea tuturor metodelor şi instrumentelor care permit elaborarea
produselor software.
Dezvoltarea unei mari aplicaţii este o problemă complexă care nu constă
numai în a programa, în sensul strict al cuvântului, aceasta presupune
parcurgerea unui anumit număr de etape, ceea ce constituie ciclul de viaţă
al unui produs software.
În plus, un mare proiect este dezvoltat de către echipe de programatori,
ceea ce obligă la descompunerea problemei în subprobleme pentru fi
repartizate între echipe, asigurarea comunicaţiei corespunzătoare între
echipe, controlul evoluţiei proiectului şi a calităţii produsului software.
Ciclul de viaţă se compune din fazele următoare:
a) Analiza şi formularea clară a problemei: constă în a stabili
funcţionalităţile, restricţiile şi obiectivele proiectului în acord cu
clientul/utilizatorul. Principala problemă a acestei faze rezidă în
comunicarea dintre conceptor şi client.
b) Specificarea: constă în determinarea funcţionalităţilor detaliate ale
produsului software ce urmează a fi realizat, fără o preocupare
deosebită pentru modalitatea de implementare efectivă.
c) Concepţia: este faza de definire a structurii modulare a produsului
software, alegerea algoritmilor corespunzători precum şi a
limbajelor de programare adecvate.
d) Programarea constă în implementarea efectivă a diferitelor module
care compun produsul software.
e) Testarea şi validarea: constă în depistarea erorilor de concepţie şi
de programare încât să se poată oferi asigurarea că produsul
software răspunde bine exigenţelor formulate iniţial.
f) Întreţinerea: este faza cea mai îndelungată a ciclului de viaţă a unui
produs software, care durează toată perioada de exploatare a
produsului. În timpul acestei faze se încearcă să se răspundă
cerinţelor utilizatorilor, fie corectând erorile apărute, fie efectuând
modificări, fie adăugând noi funcţionalităţi.
g) Documentarea: constă în regruparea tuturor informaţiilor produse
în timpul ciclului de viaţă. Documentarea nu este deci o fază proprie
a ciclului de viaţă, dar ea trebuie să se efectueze în timpul fiecărei
faze în paralel cu derularea acesteia. Documentarea trebuie să
permită înţelegerea şi modificarea ulterioară a produsului software.
Trecerea de la o fază a ciclului de viaţă la următoarea este rareori
definitivă, se întâmplă frecvent să se revină la o fază anterioară pentru a se
aduce un anumit număr de modificări. Într-adevăr, este foarte dificil să se

82
prevadă în avans toate aspectele şi în plus, în timpul fazei de întreţinere,
modificările importante cum ar fi crearea unei noi versiuni implică
dezvoltarea completă pornind de la faza de specificare. Din acest aspect
decurge noţiunea de ciclu.
Etapele ciclului de viaţă ale unui produs software sunt prezentate
schematic în figura următoare:

Analiza problemei

Specificare

Concepţie

Programare

Testare şi validare

Întreţinere

Conceptul de software este utilizat pentru a caracteriza toate programele


care sunt executate de către sistemul de calcul. Acest concept se opune
aceluia de hardware care desemnează aspectul material, fizic al sistemului
de calcul.
Execuţia unui program care este elaborat în faza de programare a ciclului
de viaţă a unui produs software constă în a furniza sistemului de calcul o
secvenţă de instrucţiuni direct interpretabile.

83
În mod obigatoriu, primele programe erau scrise în binar (limbajul
maşină), activitate dificilă şi expusă riscurilor de eroare, datorită secvenţelor
de biţi a căror semnificaţie era înscrisă într-o tabelă descriind toate operaţiile
posibile şi semnificaţia lor binară.
În continuare, pentru uşurarea activităţii de programare s-au elaborat
limbajele de asamblare.
Scrierea de programe în limbaj de asamblare rămâne o sarcină
complicată şi de asemenea programele depind de sistemul de calcul pe care
au fost concepute. Limbaje evoluate, ca de exemplu, Fortran sau Pascal au
adus o soluţie (parţială) acestor probleme.
Ca şi în cazul limbajelor de asamblare, programele scrise în limbajele de
programare evoluate trebuie să fie convertite în limbaj maşină pentru a fi
executate, iar conversia se poate efectua în două moduri diferite: traducere
sau interpretare.
Traducerea constă în a genera un program echivalent programului sursă,
dar codificat în limbajul binar al calculatorului. Traducerea este un procedeu
prin care, pornind de programul sursă, se generează un program obiect, care
se poate încărca ulterior în memorie pentru execuţie.
Interpretarea efectuează conversia şi execuţia unui program într-o
singură etapă: instrucţiunile sunt citite unele după altele şi sunt convertite
imediat în limbaj maşină prin intermediul interpretorului care realizează
execuţia lor pe măsura apariţiei. Totul se petrece ca şi când limbajul sursă ar
fi acceptat de către maşină.
Interpretarea este mai bine adaptată dezvoltării şi punerii la punct a
programelor deoarece execuţia începe imediat, iar traducerea este indicată
pentru exploatarea programelor, când nu mai este reluată traducerea.
Limbajele evoluate dispun în general de un traducător (compilator), dar
pot dispune şi de un intrerpretor (exemplul limbajului Pascal).

4.1 Limbajul de asamblare

Limbajul de asamblare este utilizat astăzi de către specialiştii în


informatică, în general pentru rezolvarea unor probleme de optimizare,
atunci când se impune exploatarea arhitecturii calculatorului şi funcţionarea
sa la nivelul operaţiilor elementare.
Limbajul de asamblare este o variantă simbolică a limbajului maşină.
Activitatea de programare este facilitată de utilizarea codurilor de operaţii
mnemonice, etichete (adrese simbolice), literale (constante numerice) şi directive
(rezervare de spaţiu de memorie, declararea unei macroinstrucţiuni etc.).

84
Spre deosebire de limbajele evoluate, limbajul de asamblare nu ascunde
nimic programatorului, permiţând accesarea tuturor resurselor sistemului şi
exploatarea facilităţilor de prelucrare ale acestuia.
O instrucţiune în limbaj de asamblare este divizată în mai multe câmpuri
care sunt separate în general prin spaţii. Numărul operanzilor din al zona de
adresă variază de la un sistem de calcul la altul între 0 şi 3. După acest câmp
este de dorit adăugarea comentariilor pentru documentare. Iată structura
tipică a unei instrucţiuni în limbaj de asamblare:

eticheta cod operaţie (mnemonic) operanzi

Codurile operaţiilor mnemonice


Codurile operaţiilor sunt simbolizate într-o tablă a codurilor mnemonice
care urmează a fi consultată la scrierea de programe în limbajul de asamblare,
mai ales dacă setul de instrucţiuni este complex (arhitecturi CISC).

Operanzi şi etichete
Spre deosebire de limbajul maşină, limbajul de asamblare permite
atribuirea de nume pentru variabile şi etichete (adrese de instrucţiuni), ceea
ce uşurează programarea.
De asemenea, operanzii pot să posede un nume care permite referirea lor,
iar fiecare registru are un nume predefinit, recunoscut de către programul de
traducere.
Exemple de operanzi şi etichete:
Tab DS 1 Definirea unei variabile Tab de un cuvânt;
Zece DC 10 Definirea constantei Zece care are val. 10;
Ciclu: MOVE Zece, A1 Transferul valorii 10 în registrul A1;
MOVE A2,Tab Transfer valoare registru A2 în variabila Tab;
JUMP Ciclu Salt necondiţionat la adresa Ciclu.

Literale
Limbajul de asamblare permite definirea valorilor întregi sau reale în
diverse baze de numeraţie (2, 8, 10 sau 16) ca şiruri de caractere, care sunt
traduse de către asamblor. Specificarea bazei de numeraţie se face prin
plasarea unui caracter particular la începutul fiecărei date. Absenţa
caracterului particular specifică o dată zecimală. Şirurile de caractere sunt de
regulă delimitate de caracterul „ ‘ ”.
Directive

85
Directivele sau pseudo-instrucţiunile sunt instrucţiuni neexecutabile
(referite prin cod mnemonic) care nu au cod maşină echivalent. Acestea sunt
indicaţii pentru asamblor (traducător) în vederea traducerii programului.
Exemple de directive:
TTL ‘Titlul programului’
Vec DS 50 Definire variabilă Vec şi rezervare 50 cuvinte;
Zero DC 0 Definire constantă Zero cu valoare 0;
PLEN 50 50 linii pe pagină (PLEN=Page Length);
END Sfârşit de program.

Expresii aritmetice
Spre deosebire de limbajele evoluate, expresiile aritmetice utilizate
pentru a calcula valoarea unei variabile, ca de exemplu în atribuirea
următoare: A = B + C / D, nu sunt admise în limbajul de asamblare şi de
aceea trebuie programate prin mai multe instrucţiuni.

Macroinstrucţiuni şi subprograme
Anumite asambloare permit structurarea programelor, ele oferă în
general posibilitatea de a grupa o secvenţă de instrucţiuni sub forma unui
subprogram sau a unei macroinstrucţiuni, în scopul modularizării
programului şi a evitării scrierii repetate a unor grupuri de instrucţiuni.

Macroinstrucţiuni
O macroinstrucţiune se construieşte prin izolarea unei secvenţe de
instrucţiuni căreia i se atribuie un nume simbolic prin care poate fi referită.
Ori de câte ori în cadrul programului se face referire la acest nume,
asamblorul, în etapa de traducere, înlocuieşte referinţa cu secvenţa de
instrucţiuni corespunzătoare.
Utilizarea macroinstrucţiunilor prezintă mai multe avantaje, şi anume:
 extinderea setului de instrucţiuni, deoarece fiecare macroinstrucţiune
se utilizează ca o altă instrucţiune;
 reducerea şi structurarea programelor, care conduce la înţelegerea şi
modificarea uşoară a acestora;
 economisirea timpului de programare.
Instrucţiunile care servesc pentru definirea şi delimitatea
macroinstrucţiunilor (de exemplu, MACRO şi ENDM) sunt cazuri tipice de
directive; în timpul asamblării, fiecare apel al unei macroinstrucţiuni este
înlocuit prin corpul macroinstrucţiunii şi cele două pseudo-instrucţiuni sunt
eliminate.
Exemplu: Calculul cubului unui număr:

86
MACRO CUB (val, valcub)
MOVE val, D1
MOVE val, D2
MUL D1, D2 (D2:= D1  D2)
MUL D1, D2
MOVE D2, valcub
ENDM

Subprograme
Subprogramele sunt definite ca şi macroinstrucţiunile, având de
asemenea scopul de a evita repetarea scrierii unei secvenţe de instrucţiuni ce
va fi utilizată de mai multe ori.
O diferenţă esenţială faţă de macroinstrucţiune rezidă în faptul că
instrucţiunile care compun subprogramul constituie o entitate bine separată
de programul principal, iar această separare se păstrează şi după traducere,
încât subprogramul se găseşte o singură dată în memorie şi doar la execuţia
programului se satisfac referinţele la un subprogram al său.
Această manieră de abordare a programării conduce la avantaje
suplimentare faţă de utilizarea macroinstrucţiunilor, deoarece permite
minimizarea taliei codului executabil, ceea ce nu este cazul
macroinstrucţiunilor.
Problemele care se manifestă în situaţia utilizării subprogramelor se
referă în special la asigurarea salvării adresei de revenire în timpul
execuţiei unui subprogram. Adresa de revenire este adresa instrucţiunii care
urmează după instrucţiunea de apel a subprogramului.
Deci, principala diferenţă între o macroinstrucţiune şi un subprogram
este aceea că apelurile la o macroinstrucţiune sunt înlocuite prin corpul
macroinstrucţiunii în timpul traducerii, pe când apelurile la un subprogram
sunt tratate în timpul execuţiei.

Transmiterea parametrilor
Un program poate să schimbe date cu macroinstrucţiunile şi
subprogramele sale prin intermediul parametrilor. Un parametru este o
variabilă al cărei nume este cunoscut, dar al cărei conţinut nu este precizat
decât în momentul execuţiei. O macroinstrucţiune sau un subprogram se
scrie utilizând parametrii formali care vor fi înlocuiţi prin parametrii
efectivi corespunzători datelor reale care sunt tratate.
Substituţia parametrilor formali cu cei efectivi se realizează la traducere,
pentru macroinstrucţiuni, şi la execuţie, pentru subprograme.

87
Pentru subprograme există mai multe tehnici de transmitere a
parametrilor:
a) Transmiterea prin valoare constă în recopierea valorii de transmis
într-o zonă cunoscută de subprogram, care poate fi o zonă de
memorie sau un registru. În acest fel, subprogramele acţionează
asupra unei copii a parametrilor, orice modificare a parametrului nu
este posibilă decât în interiorul subprogramului, iar la revenire în
programul apelant parametrul regăseşte valoarea sa iniţială, ceea ce
permite o anumită protecţie a parametrilor.
b) Transmiterea prin referinţă constă în a transmite către
subprogram adresele parametrilor. Subprogramul lucrează deci
efectiv asupra datelor programului apelant, deci orice modificare a
valorii parametrului în interiorul subprogramului este reflectată la
revenire în programul apelant.

Salvarea stării maşinii


Salvarea stării maşinii constă în a salva starea registrelor CPU (în alte
registre CPU prevăzute în acest scop sau în memoria centrală) pentru a
permite executarea unui alt program şi la sfârşitul execuţiei acestuia,
reluarea execuţiei primului.
Spre deosebire de macroinstrucţiuni, unde expandarea (înlocuirea
apelului prin corpul macroinstrucţiunii) se realizează la traducere, în cazul
subprogramelor este necesară salvarea stării maşinii la apelul acestora.
Într-adevăr, apelul unui subprogram constă în trecerea controlului CPU-
ului acestui subprogram, care se comportă ca un program independent şi
care trebuie să fie capabil să redea controlul programului apelant la sfârşitul
execuţiei sale. Primele instrucţiuni ale subprogramului servesc la salvarea
stării diverselor registre, iar ultimele instrucţiuni restaurează aceste valori
salvate, revenind la contextul anterior apelului.

Recursivitate
Un subprogram este recursiv dacă poate să se autoapeleze (direct sau
indirect).
Problema unui subprogram recursiv este că în timpul fiecărui apel,
trebuie salvată starea maşinii. Datorită faptului că nu se poate utiliza aceeaşi
zonă de memorie pentru salvare, se adoptă o soluţie bazată pe utilizarea unei
stive care lucrează după principiul LIFO Last In, First Out, în care se
salvează starea maşinii pe măsura activării apelurilor recursive (este
necesară o condiţie de sfârşit pentru apelurile recursive).

88
Figura următoare ilustrează diferenţa dintre o macroinstrucţiune şi un
subprogram.

macroinstrucţiune program subprogram subprogram

salvare
stare
program
program
restaurare
stare
revenire

program

apel macroinstrucţiune
instrucţiune normală

apel subprogram

MACROINSTRUCŢIUNE SUBPROGRAM

4.2 Limbaje de programare

Un limbaj este o modalitate de exprimare şi comunicare a gândurilor.


Există o multitudine de limbaje: limbaje orale, scrise, limbajul semnelor (de
exemplu, limbajul surdo-muţilor) şi multe alte limbaje care utilizează diverse
moduri de transmisie (de exemplu, limbajul albinelor).

89
Un limbaj informatic cuprinde:
 un alfabet: mulţimea simbolurilor elementare disponibile;
 nume sau identificatori: grupe de simboluri ale alfabetului (cu
anumite restricţii: număr de caractere, tipul primului caracter etc.);
 fraze sau instrucţiuni: secvenţe de nume şi simboluri de punctuaţie
care respectă aspectele sintactice şi semantice ale limbajului.
Limbajele informatice, spre deosebire de limbajele naturale, sunt
structurate, riguros neambigue şi pot fi definite în mod formal.
Limbajele de asamblare au fost primele limbaje informatice şi ele depind
de arhitectura sistemelor de calcul.
Limbajele evoluate HLL: High Level Languages au apărut mai târziu şi
permit comunicarea cu sistemul de calcul fără a ţine seama de arhitectura sa.
În informatică se disting mai multe categorii de limbaje: limbajele de
programare şi limbajele de comandă sunt cele mai utilizate, dar există de
asemenea şi limbaje de analiză şi limbaje de specificare, care ajută în
timpul primelor faze de dezvoltare a produselor software.
Scrierea unui program se realizează prin utilizarea simbolurilor
limbajului de programare pentru constituirea frazelor sau instrucţiunilor care
trebuie să respecte sintaxa limbajului.
Cele două modalităţi de reprezentare a sintaxei unui limbaj sunt:
 notaţia BNF Backus Naur Form;
 diagramele sintactice.
Prezentăm în continuare un exemplu de sintaxă a unui limbaj foarte
simplu care permite definirea identificatorilor (încep întotdeauna cu o literă),
întregii fără semn, expresiile aritmetice simple şi instrucţiunea de atribuire.
Pentru notaţia BNF, semnul „  ” indică o alternativă, semnele „< ” şi
„ > ” delimitează obiectele limbajului şi semnul „ := ” indică atribuirea.
< literă > ::= a b c d . . .y z
< cifră > ::= 0 1 2 3 4 5 6 7 8 9
< identificator > ::= < literă >  <identificator > < literă > 
 < identificator > < cifră >
< întreg > ::= < cifră >  < întreg > < cifră >
< termen > ::= < întreg >  < identificator >
< operator > ::= + -  /
<expresie > ::= < termen > 
 <termen> < operator><expresie>
< atribuire > ::= < identificator > := < expresie >

Utilizând diagramele sintactice, prezentăm acelaşi exemplu de definire a


sintaxei limbajului:

90
literă
identificator literă
cifră

întreg cifră

întreg

termen
identificator

-
operator

expresie termen

operator

atribuire identificator := expresie

91
Concepte de bază ale limbajelor evoluate
Limbajele evoluate permit uşurarea activităţii de programare printr-o
apropiere de limbajul natural, dar cu respectarea exigenţelor de rigoare şi
neambiguitate.
Primele concepte de bază ale limbajelor de programare evoluate se
refereau la independenţa faţă de sistemul de calcul, ceea ce a permis
elaborarea unor instrucţiuni posedând un nivel semantic superior limbajului
de asamblare.
Elaborarea de limbaje de programare evoluate a vizat încă de la început
trei direcţii importante, şi s-a concretizat prin trei categorii de limbaje:
a) limbaje bazate pe conceptele de algoritm şi prelucrarea datelor cu
caracter ştiinţific (Fortran, Algol);
b) limbaje bazate pe prelucrarea datelor (Cobol);
c) limbaje bazate pe prelucrarea listelor (Lisp).
Limbajele din primele două categorii sunt limbaje procedurale care
furnizează o descriere detaliată a algoritmilor de rezolvare a problemelor, iar
limbajele din a treia categorie sunt limbaje funcţionale, care subliniază
aspectul funcţional al rezolvării unei probleme, fără a intra în detalii.
Orientarea algoritmică a permis în continuare dezvoltarea limbajelor Algol
60, Algol 68, Fortran II, Fortran IV, Fortran 66, Fortran 77, Fortran 90,
Pascal, C, Modula-2, Ada şi C++, care furnizează metodologii bazate pe
conceptele de programare structurată, abstractizare, modularitate etc.
A doua orientare, bazată pe prelucrarea datelor a rămas fidelă limbajului
Cobol, dar a evoluat spre sisteme de gestiune de baze de date care permit
rezolvarea problemelor specifice bazelor de date.
Limbajul Prolog, instrument de bază în domeniul inteligenţei artificiale, a
rezultat din abordarea funcţională şi aduce nou, în afară de prelucrarea listelor, un
mecanism de inferenţă foarte util pentru realizarea sistemelor expert.
Asistăm astăzi la o oarecare convergenţă între limbajele orientate
obiect şi bazele de cunoştinţe, ceea ce permite gruparea şi unificarea
conceptelor de bază ale diverselor orientări.
Vom prezenta în continuare o scurtă descriere pentru câteva limbaje de
programare dintre cele mai utilizate:
 Fortran Formula Translator este primul limbaj algoritmic, utilizat în
principal pentru rezolvarea problemelor cu caracter ştiinţific. El produce
cod eficace, utilizează o mare cantitate de biblioteci matematice şi a
introdus concepte importante, ca de exemplu, structurarea expresiilor
aritmetice, subprograme, compilarea independentă a subprogramelor.
Limbajul a evoluat mereu, versiunea Fortran 90 permite programarea
paralelă şi concurentă specifică supercalculatoarelor.

92
 Cobol Common Business Oriented Language este un limbaj destul de
utilizat în lume, şi este adaptat aplicaţiilor de gestiune care permit un acces
uşor la fişiere şi baze de date. Inconvenientele utilizării sale provin din
aspectul „stufos” al scrierii şi dificultatea de structurare a programelor.
 Algol Algorithmic Oriented Language a avut o influenţă primordială
asupra limbajelor actuale. Definit pentru aplicaţii ştiinţifice, limbajul nu a
reuşit să se impună din cauza complexităţii sale, lipsei de soliditate a
intrărilor/ieşirilor şi lipsa eficacităţii. Totuşi, Algol a introdus conceptul
de structurare, cu structuri de blocuri, structuri de control, proceduri,
recursivitate. Este primul limbaj definit în notaţia BNF şi a evoluat în
Algol 60, Algol 68, Algol W dar a rămas în mediul academic.
 Lisp List Processing a fost conceput pentru manipularea expresiilor şi
funcţiilor simbolice. Caracteristicile sale sunt: capacitatea de tratare a
listelor, un număr mic de operatori de bază, un număr mare de paranteze şi
recursivitatea care joacă un rol de seamă în parcurgerea listelor. Limbajul
este utilizat curent în inteligenţa artificială. Datorită lipsei de eficacitate pe
sisteme de calcul tradiţionale, anumiţi constructori au dezvoltat maşini
Lisp, care acceptă acest limbaj ca limbaj maşină, având o arhitectură
particulară, bazată pe noţiunea de stivă.
 Basic Beginner’s All-purpose Symbolic Instruction Code este un
limbaj rudimentar, care a fost dezvoltat doar în scop didactic. El a
devenit un limbaj răspândit datorită dezvoltării microcalculatoarelor
care, la început nu aveau capacitatea de a utiliza alte limbaje.
 PL/1 Programming Language number 1 este o realizare ambiţioasă,
un limbaj aproape universal, menit să înlocuiască limbajele Fortran,
Algol şi Cobol utilizate în acea epocă. Din cauza complexităţii sale,
lipsa de omogenitate şi de rigoare limbajul nu a cunoscut o mare
răspândire, limitându-se la calculatoarele din familia IBM.
 Pascal, care poartă numele matematicianului francez creator al uneia
dintre primele maşini aritmetice de calcul din secolul XVII, a fost
dezvoltat de către elveţianul Niklaus Wirth. Acest limbaj provenit
din Algol căruia îi preia conceptele, este bazat pe o mare simplitate
şi este destinat înainte de toate învăţării programării.
 Modula-2 este încă un limbaj dezvoltat de Wirth. Limbajul este un
descendent al limbajului Pascal, căruia îi adaugă noţiunea de
modularitate care permite compilarea independentă a modulelor.
 Smalltalk este un limbaj care caracterizează o nouă tendinţă de
programare bazată pe conceptul de obiect. El permite o interacţiune
grafică cu sistemul, bazată pe utilizarea ferestrelor şi a meniurilor,
ceea ce constituie o inovaţie în domeniul programării.

93
 Prolog Programmation Logique (elaborat în 1972 de către
Colmerauer) este un limbaj care preia conceptele limbajului Lisp,
adăugând un mecanism de inferenţă utilizat la realizarea sistemelor
expert. Japonezii şi-au pus mari speranţe în acest limbaj pentru
proiectul de sisteme de calcul de generaţia a cincea.
 C, un succesor al limbajelor BCPL şi B, este un limbaj orientat spre
programare de sistem. Succesul limbajului se datorează utilizării
sale pentru dezvoltarea sistemului de operare UNIX. C este un
limbaj relativ simplu la nivel de concepte, codul generat de
compilator este eficace, dar sintaxa permite scrierea într-o linie a
instrucţiunilor foarte complexe, care devin aproape ilizibile.
 Ada, al cărui nume aduce omagiu Adei Byron (sec. XIX),
considerată ca prima informaticiană, este un limbaj conceput pentru
departamentul apărării al SUA. El preia conceptele limbajelor
Pascal şi Modula-2, adăugând concepte de timp real, paralelism,
genericitate şi gestiunea excepţiilor.
 C++ este un succesor al limbajului C, dezvoltat de către Bjarne
Stroustrup la începutul anilor ‘80. Acest limbaj,evoluţie naturală a
limbajului C, reia conceptele acestui limbaj, la care adaugă un anumit
număr de concepte legate de programarea orientată obiect, ca de
exemplu, noţiunea de clasă de obiecte, moştenire între clase etc.

Orientarea obiect
Evoluţia programării clasice se poate rezuma în felul următor:
a) Programarea procedurală procedural programming: accentul este
pus pe algoritmi, codul este repartizat în proceduri, iar structurile de date
nu sunt luate în considerare. Este cazul limbajelor Fortran sau C.
b) Încapsularea şi abstractizarea datelor data hidding and
abstraction: apare noţiunea de modul, care permite descompunerea
codului în diferite module. Datele sunt închise în interiorul
modulelor ceea ce constituie tipurile abstracte de date ADT:
Abstract Data Type. Practic, un ADT poate fi văzut ca o „cutie
neagră”, iar seviciile (metode) sunt oferite prin intermediul unei
interfeţe. Este cazul limbajelor Modula-2 şi Ada.
c) Programarea orientată obiect object oriented programming: reia
conceptele de tipuri abstracte de date dar se insistă asupra noţiunii
de reutilizare a obiectelor sistemului. În acest sens, se determină
principalele modele de date necesare, care se vor numi clase de
obiecte şi în continuare se stabilesc metodele care vor manipula
aceste modele. Un program se compune deci dintr-un ansamblu de

94
obiecte care interacţionează între ele trimiţându-şi mesaje care
activează metodele specifice fiecărei clase de obiecte. Este cazul
limbajelor Smalltalk, Eiffel, C++, Objective-C.

Tipuri abstracte de date


Un tip abstract de date permite descrierea unei clase de structuri de date
prin lista funcţiunilor (metode) disponibile asupra structurilor de date şi nu
prin implementarea lor.

Clase şi obiecte
O clasă de obiecte corespunde implementării unui tip abstract de date.
Definiţia unei clase descrie comportamentul tipului său abstract prin specificarea
interfeţei tuturor operaţiilor (metode) aplicabile asupra tipului abstract.
Definiţia unei clase comportă de asemenea detalii cu privire la
implementarea unor astfel de structuri de date sau codul sursă care
implementează metodele.
Un obiect object este o variabilă a cărei tip este o clasă. El reprezintă o
instanţă (realizare) a unei clase. Acţiunile pot fi aplicate asupra acestui
obiect invocând metodele definite în clasă, care se realizează printr-un
procedeu numit trimitere de mesaje obiectelor clasei.
Clasele sunt entităţi definite în codul sursă al unui program, ele descriu
de o manieră statică o mulţime de obiecte (pot fi considerate şi ca tipuri de
date), în timp ce obiectele sunt elementele dinamice, ele nu există decât la
execuţie şi corespund instanţelor clasei.

Mesaje
Obiectele pot comunica între ele trimiţându-şi mesaje prin care se
solicită efectuarea unei anumite operaţii asupra acestor obiecte. Mulţimea
tipurilor de mesaje proprii unui obiect corespunde interfeţei sale.

Polimorfism
Polimorfismul permite efectuarea unei acţiuni prin trimiterea unui mesaj
la un obiect pentru care sunt posibile mai multe instanţe de execuţie. Această
capacitate este foarte importantă atunci când acelaşi mesaj poate fi îndeplinit
în moduri diferite pentru tipuri diferite de obiecte.
Limbajele orientate obiect permit trimiterea mesajelor identice spre
obiecte care aparţin unor clase diferite (dar derivate din clasa de bază).
Polimorfismul constă în esenţă în posibilitatea asocierii mai multor
implementări ale aceluiaşi mesaj, iar sistemul de calcul trebuie să fie în
măsură să stabilească implementarea corespunzătoare mesajului transmis.

95
Acestă decizie (constând în legarea mesajului de implementarea
corespunzătoare) se poate lua fie la compilare early sau static bilding, fie la
execuţie late sau dynamic bilding.

Moştenirea şi ierarhizarea claselor


Prin mecanismul moştenirii inheritance, programarea orientată obiect
permite definirea subclaselor. O subclasă, numită şi clasă derivată permite
caracterizarea comportamentului unei mulţimi de obiecte care moştenesc
caracteristicile clasei lor „părinte”, dar care poate de asemenea să posede
caracteristici particulare proprii, pe care „părintele” nu le are.
Utilizarea subclaselor permite diminuarea costului şi complexităţii
programelor, deoarece subclasele facilitează reutilizarea claselor existente,
permiţând în acelaşi timp modificarea lor.

Genericitate
Genericitatea se exprimă prin capacitatea de a defini clase
parametrizabile. De exemplu, presupunem că este necesară o stivă de
numere întregi şi o stivă de numere reale. În locul definirii celor două tipuri
de stivă se va proceda la definirea unei clase parametrizată numită stivă, din
care se vor genera cele două clase dorite.
Genericitatea şi moştenirea corespund unor necesităti diferite şi
generează structuri diferite: moştenirea favorizează rafinamente succesive
ale unei aceeaşi clase rezultând astfel o structură pe verticală, în timp ce
genericitatea permite definirea unei clase de bază parametrizată care se poate
instanţia de mai multe ori cu tipuri diferite, rezultând astfel o structură pe
orizontală. Figura următoare evidenţiază această situaţie.

Moştenire Genericitate
(structură verticală) (structură orizontală)

96
Inteligenţa artificială şi sistemele expert
Inteligenţa artificială este domeniul informaticii care propune simularea
pe sistemele de calcul a comportamentului inteligent al omului. Sunt
implicate domeniile perceperii, înţelegerii, luării deciziilor, învăţării.
Această orientare a condus la unele rezultate notabile, în special în unele
domenii: teoria jocurilor, demonstrarea teoremelor, recunoaşterea formelor,
recunoaşterea parolelor, înţelegerea limbajelor naturale, rezolvarea
problemelor care necesită expertiză legată de un domeniu specific (de
exemplu, diagnosticul medical), matematici simbolice etc.
Inteligenţa artificială trebuie să permită rezolvarea problemelor pentru
care abordarea algoritmică este ineficientă sau chiar imposibil de aplicat. Un
program al inteligenţei artificiale se caracterizează prin utilizarea
simbolurilor în locul informaţiilor alfanumerice.

Sisteme expert
Sistemele expert constituie cu siguranţă domeniul inteligenţei artificiale
care a cunoscut cea mai mare dezvoltare. Un sistem expert este un program
care utilizează intensiv cunoştinţa în scopul rezolvării problemelor care
necesită în mod normal expertiza umană.
Într-un sistem expert există o separaţie netă între programe şi cunoştinţe.
Arhitectura de bază a unui sistem expert cuprinde trei părţi:
a) Baza de fapte este un fel de bază de date care regrupează faptele şi
aserţiunile vizând problema tratată;
b) Baza de reguli conţine cunoştinţele care permit manipularea
faptelor din baza de fapte. Cunoştinţele se exprimă sub formă de
reguli de producţie. O regulă comportă o parte stângă, exprimând o
condiţie (dacă) şi o parte dreaptă conţinând concluzii (atunci);
c) Motorul de inferenţă exploatează baza de cunoştinţe (baza de
fapte + baza de reguli) asociind faptele şi regulile pentru a formula
un raţionament asupra problemei puse. Pentru aceasta, pornind de la
baza de fapte, el determină mulţimea regulilor a căror parte stângă
este verificată, faptele conţinute în partea dreaptă adăgându-se la
baza de fapte. În continuare, motorul de inferenţă aplică aceste
reguli (înlănţuire înainte) pentru a ajunge la o concluzie, procesul
oprindu-se când nu se mai pot genera fapte noi. Se poate de
asemenea porni de la concluzie, inferenţele propagându-se invers
(înlănţuire înapoi). Ele determină noi subscopuri mai simplu de
verificat până la găsirea părţilor stângi ale regulilor corespunzătoare
faptelor din baza de fapte. Un anumit număr de limbaje (Lisp şi
Prolog) permit dezvoltarea cu uşurinţă a sistemelor expert simple.

97
4.3 Etapele dezvoltării unui program

Dezvoltarea unui program, de la analiza problemei până la punerea sa la


punct, necesită numeroase instrumente software constituite într-un mediu de
programare, care utilizează serviciile sistemului de operare, în special
sistemul de gestiune al fişierelor. Figura următoare prezintă grafic un mediu
de programare minim:
idee

Editor de texte

program sursă

Traducător asamblor
compilator
program obiect
subprograme subprograme
de bibliotecă traduse separat

Editor de legături

program obiect

Încărcător

program executabil

execuţie

Corector

98
Elementele clasice ale unui mediu de programare sunt următoarele:
editorul de texte, traducătorul (compilator sau asamblor), editorul de
legături, programul încărcător şi programul corector.

Editorul de texte
Editorul de texte text editor este un program interactiv care permite
preluarea unui text pornind de la tastatură şi stocarea sa într-un fişier.
Informaţiile sunt de tip text, adică o mulţime de caractere, structurate în linii.
Principalele funcţiuni ale unui editor de texte sunt:
 vizualizarea unei părţi a textului;
 deplasarea şi poziţionarea în fişier (se indică poziţia curentă);
 modificarea textului prin inserare, modificare, ştergere;
 regăsirea şirurilor de caractere particulare.
Editorul poate fi utilizat atât pentru tastarea textului sursă al unui
program cât şi pentru introducerea datelor necesare programului.
Vom evidenţia două dintre cele mai importante tipuri de editoare:
a) editor sintactic, adaptat prelucrării programelor sursă, care verifică
sintaxa programelor pe măsura tastării acestora, permiţând de
asemenea gestionarea automată a structurilor sintactice proprii
limbajului de programare utilizat;
b) procesor de texte, destinat tratării textelor. Acest tip de editor oferă
funcţionalităţi mult mai pronunţate pentru manipularea caracterelor:
utilizarea literelor accentuate, fonturi diferite (adică diferite seturi de
caractere), alinierea textului, inserare de desene etc., mai general se
zice că aceste editoare oferă facilităţi de punere în pagină pentru
scriere de scrisori, articole, cărţi etc.

Compilatorul
Un compilator este un program sistem care traduce un program sursă
scris într-un limbaj de programare de nivel înalt în program obiect.
Activitatea compilatorului se divide în două mari componente:
a) faza de analiză, care cuprinde următoarele etape:
 analiza lexicală;
 analiza sintactică;
 analiza semantică.
b) faza de sinteză, care cuprinde următoarele etape:
 generarea codului intermediar;
 optimizarea codului;
 generarea codului obiect.
Activitatea compilatorului este prezentată schematic astfel:

99
program
sursă

tabela de analiza lexicală arbore sintactic


simboluri
analiza sintactică

analiza semantică

generarea codului
intermediar

optimizarea
codului

generarea codului
obiect
Compilator

program obiect

Analiza lexicală
Analiza lexicală este prima fază a compilării. Rolul său major constă în
citirea secvenţei de caractere care constituie programul sursă şi producerea
unor secvenţe de elemente sintactice ale limbajului.
Identificatorii, de exemplu numele de variabile, sau de proceduri ca şi
atributele lor sunt stocate într-o tabelă de simboluri, în timp ce informaţiile
inutile pentru compilator (comentariile) sunt eliminate.

100
Analiza sintactică
Analizorul sintactic primeşte o listă de elemente sintactice (cuvinte
rezervate, identificatori, operatori aritmetici, semne de punctuaţie etc.)
elaborată de către analizorul lexical, verifică corectitudinea ei în raport cu
sintaxa limbajului şi generează arborele sintactic al programului.
Sunt posibile două abordări pentru generarea arborelui sintactic:
 ascendentă: se analizează elementele componentr ale frazei de tratat
şi se caută regulile care permit ascensiunea spre rădăcină;
 descendentă: se porneşte de la rădăcină şi se aplică regulile care
permit construirea frazei dorite.

Analiza semantică
Analiza semantică vizează sensul şi semnificaţia frazelor limbajului, utilizând
arborele sintactic pentru a identifica operatorii şi operanzii instrucţiunilor.
Sarcina principală a unui analizor semantic este verificarea concordanţei
tipurilor, ceea ce revine la a verifica dacă fiecare operator acţionează asupra
operanzilor care sunt autorizaţi prin limbaj. Pentru efectuarea acestor verificări,
analizorul semantic utilizează informaţiile care sunt stocate în tabela de simboluri.

Generarea codului intermediar


După etapele fazei de analiză, se procedează la generarea programului în
cod obiect. O metodă răspândită constă în divizarea acestei sarcini în două
etape: generarea codului intermediar şi generarea codului obiect.
Codul intermediar se poate defini ca un cod al unei maşini abstracte, care
trebuie să posede două proprietăţi: să fie uşor de generat pornind de la
arborele sintactic al unui program şi să fie uşor de tradus în cod obiect.
Pornind de la arborele sintactic al unui program, compilatorul generează un
flux de instrucţiuni simple care se aseamănă cu macroinstrucţiunile, dar contrar
asamblorului, acestea nu fac referire explicită la registrele sistemului.

Optimizarea codului
Optimizarea codului constă în ameliorarea codului pentru a-l face mai
rapid de executat şi mai puţin „încurcat” în memorie, şi vizează în special
eliminarea redondanţelor şi evaluarea expresiilor care utilizează constante.
Optimizarea conduce la o creştere substanţială a timpului de compilare,
deci este de preferat evitarea acestei faze în timpul elaborării programelor.
Optimizarea codului joacă un rol determinant pentru sistemele de calcul
care utilizează un procesor RISC, datorită complexităţii compilatoarelor
pentru astfel de maşini, care utilizează un număr mare de registre în vederea
reducerii numărului de accese la memoria centrală.

101
Generarea codului obiect
Generarea codului obiect este fază finală a compilării, care generează
codul obiect relocabil, adică relativ la originea 0. Fiecare instrucţiune a
codului intermediar este tradusă într-o secvenţă de instrucţiuni în cod obiect.
Generarea codului obiect atribuie poziţii în memorie pentru datele şi
instrucţiunile programului.

Tabela de simboluri
În timpul compilării este necesară descrierea identificatorilor şi a
caracteristicilor acestora. Tabela de simboluri permite gruparea acestor
informaţii care sunt puse la dispoziţia diferitelor faze ale compilatorului.
În tabelă se găsesc numele variabilelor, constantelor şi procedurilor.
Fiecărei intrări din tabelă i se asociază o înregistrare care conţine numele
obiectului considerat şi caracteristicile proprii (tip, adresă numerică, numărul
şi tipul parametrilor etc.). Accesul la această tabelă trebuie să fie rapid,
deoarece toate fazele compilării pot utiliza tabela de simboluri.

Tratarea erorilor
În activitatea practică de programare s-a constatat că este dificilă scrierea
programelor fără erori şi din această cauză, un bun compilator trebuie să
facă posibilă detectarea şi corectarea acestor erori.
La sfârşitul compilării se întocmeşte un raport al erorilor depistate şi se
încearcă specificarea cauzei care a generat eroarea precum şi poziţia sa în
cadrul textului sursă.
Un program scris într-un limbaj de pogramare evoluat poate conţine erori
de natură diferită:
a) erori lexicale: erori de ortografiere a identificatorilor sau cuvintelor
rezervate, caractere ilegale etc.
b) erori sintactice: constituie majoritatea erorilor de programare şi se
referă la: expresii aritmetice sau logice incorecte, erori de structurare
a blocurilor, lipsa separatorilor etc.
c) erori semantice: identificatori nedeclaraţi, incompatibilitate între
operatori şi operanzi etc.
d) erori logice: erori aritmetice de tipul împărţirii cu zero, rădăcină
pătrată dintr-un număr negativ, depăşirea limitelor unui tablou, ciclu
infinit, adresare incorectă etc.
Erorile din primele trei categorii sunt detectate de compilator în timpul
analizei cu acelaşi nume (analiza lexicală, sintactică, semantică), şi sunt
relativ uşor de corectat deoarece compilatorul indică prezenţa lor.

102
Erorile logice sunt vizibile doar la execuţie şi au ca efect fie efectuarea
unor calcule eronate, fie oprirea execuţiei programului. Acestea sunt erorile
cele mai dificil de detectat şi corectat, şi la fiecare tentativă de corectare
trebuie reluat ciclul compilare - execuţie - testare.

Editorul de legături
Un editor de legături linkage editor este un produs software ce permite
combinarea mai multor programe obiect, obţinându-se un singur modul obiect.
Figura următoare prezintă un exemplu de editare de legături pentru un
program care conţine două subprograme traduse şi stocate în fişiere separate,
şi care face de asemenea apel la două module de bibliotecă care sunt traduse
în prealabil şi conservate în cod obiect.

subprogram program principal subprogram


(cod sursă) (cod sursă) (cod sursă)

traducere traducere traducere


modul de modul de
subprogram program principal subprogram bibliotecă bibliotecă
(cod obiect) (cod obiect) (cod obiect) (cod obiect) (cod obiect)

editare de legături

program
complet
executabil

103
Dezvoltarea unor programe complexe se realizează prin descompunerea
acestora în module care se traduc independent, deci un program poate fi
constituit din mai multe fişiere (sau subprograme), unul dintre fişiere
conţinând în mod obligatoriu programul principal.
Toate aceste fişiere sunt traduse separat, ele pot utiliza subprograme care
se găsesc în alte fişiere, ceea ce dă naştere la referinţe exterioare.
Există două tipuri de referinţe exterioare:
a) posibilitatea ca un modul să apeleze alt modul sau subprogram de
bibliotecă;
b) posibilitatea ca un modul să fie referit de un alt modul;
Referinţele exterioare unui modul ridică probleme deosebite pentru
programul traducător care nu poate satisface referinţele exterioare ci doar
întocmeşte o listă a acestora pe care o transmite editorului de legături.
Editorul de legături preia modulele independente, le grupează şi satisface
referinţele exterioare pentru a forma un program complet, care este executabil.

Programul încărcător
Programul obiect care rezultă în urma editării de legături, trebuie să fie
încărcat în memoria calculatorului pentru a putea fi executat. Programul
încărcător loader, care este de obicei cuplat cu editorul de legături
realizează încărcarea programului obiect la adresa sa de încărcare.
Există două tipuri de programe încărcătoare:
a) încărcător absolut, specific vechilor sisteme de calcul care permite
încărcarea programului (unic în memorie) la o adresă fixată în avans,
ca şi toate adresele din cadrul programului.
b) încărcător relocabil, specific noilor tipuri de sisteme
multiprogramate, care utilizează pentru încărcare în memorie
tehnica relocării. O modalitate de realizare a relocării este aceea a
utilizării indicatorului de relocare de către programul traducător în
câmpul de adresă al instrucţiunii. Relocarea se mai poate realiza prin
intermediul unui registru de bază, astfel:
 se traduce programul în raport cu adresa 0 şi se realizează
editarea de legături;
 se alege un registru de bază printre cele disponibile;
 se depune în registrul de bază adresa de bază (adresa absolută a
programului);
 se încarcă programul în memorie, pornind de la adresa de bază, fără
modificarea adreselor programului. În timpul execuţiei, la fiecare
referire a unei adrese, sistemul de calcul efectuează operaţiile:

104
adresa efectivă = adresa de bază + adresa referită.
6 STRUCTURI DE DATE

6.1 Tipuri şi structuri

Un sistem de calcul este programat pentru prelucrarea instrucţiunilor. Un


program este un ansamblu de instrucţiuni şi date. În capitolele precedente au
fost introduse conceptele esenţiale ale programării, instrucţiuni în cod
maşină şi limbaje de programare. Prezentul capitol se referă la organizarea
informaţiilor de prelucrat în memoria calculatorului.
Sistemul de calcul defineşte la nivel hardware un set de instrucţiuni
elementare şi câteva reprezentări ale datelor elementare.
O dată structurată se poate defini ca fiind o colecţie de date elementare.
O astfel de colecţie se mai numeşte structură de date.
Structurile de date au apărut la nivelul limbajelor de programare evoluate
care definesc structuri abstracte asupra instrucţiunilor, de exemplu,
macrodefiniţii, proceduri, funcţii, subprograme, etc. Ele definesc de
asemenea structuri de date precum variabile dublă precizie, numere
complexe, vectori, şiruri de caractere etc.
Exemple de structuri de date întâlnite la diferite nivele de abstractizare
sunt prezentate în figura următoare:

Arbori Stive LIFO Fişiere


Nivel aplicaţie Tabele Cozi FIFO Liste

Mulţimi Înregistrări Tablouri

Nivel Variabile logice Vectori


limbaj
Variabile întregi Variabile
Variabile
reale
caracter

Numere
Memorie în virgulă
mobilă
Nivel maşină
Cuvinte
Numere întregi
Octeţi
Registre
Biţi
105
Structurile de date sunt construite pornind de la datele elementare
realizate la nivel maşină. Utilizatorul poate să lucreze şi cu informaţii mai
complexe , deci la un nivel superior de abstractizare, fără să ţină seama de
detaliile implementării fizice a acestor structuri care sunt „ascunse” de
limbajul de programare şi software-ul asociat (traducător, interpretor, etc.).
Utilizatorul poate defini structuri de date şi mai complexe (arbori, tabele,
liste, etc.) utilizând datele structurate la nivelul limbajului de programare.
Pentru a introduce o nouă structură abstractă se procedează astfel :
- se defineşte structura informaţiei;
- se definesc operaţiile aplicabile acelei structuri;
- se lucrează cu această informaţie structurată la acest nivel de
abstractizare, fără a se ţine seamă de detaliile de implementare;
Există un mare număr de structuri de date. Vom prezenta câteva
exemple dintre structurile cele mai utilizate: vectori, tablouri, liste, arbori,
cozi, stive şi tabele.

Vectori
Vectorii vectors sunt structuri foarte utile, folosite de majoritatea
limbajelor de programare (procesoarele vectoriale suportă vectorii la nivel
hardware). Un vector este o mulţime finită şi ordonată de elemente, toate de
acelaşi tip. El este definit prin numărul de elemente, ca şi prin tipul şi
mărimea lor, stabilindu-se o corespondenţă imediată între structura abstractă
şi organizarea în memorie. Figura următoare prezintă schematizat structura
unui vector:
1 2 3 4 5 6 7 n-1 n

Tablouri
Un tablou array este o colecţie multidimensională de obiecte de
acelaşi tip. Un tablou cu o singură dimensiune este un vector. Fiecare
element al tabloului este reperat printr-un set de indici subscripts. Accesul
la informaţia conţinută într-un tablou este deci aleator. Realizarea unui
tablou multidimensional utilizează vectori, iar specificarea dimensiunilor
necesită o declaraţie în cadrul programului.

Liste
Listele lists sunt structuri suple capabile să conţină un număr
nedeterminat de obiecte. Dacă fiecare obiect este accesibil prin cel precedent

106
datorită unui pointer, atunci avem de a face cu o listă legată sau înlănţuită
linked list. Un astfel de exemplu este prezentat în figura următoare:
Pointer către
elementul următor

element element element


Există de asemenea liste dublu înlănţuite care pot fi parcurse în ambele
sensuri, fiecare element fiind compus dintr-un obiect şi doi pointeri. Evident,
realizarea unei astfel de liste se bazează pe noţiunea de pointer. Se spune că
un pointer înlănţuieşte elementele sau pointează, asupra unui element.
Pointerul este o variabilă a cărei valoare corespunde unei adrese.
Schimbând un pointer, se poate insera un nou element într-o listă, iar prin
simpla modificare a pointerilor se pot suprima elemente dintr-o listă.

Arbori
Arborele este o structură constituită din noduri legate prin arce. Fiecare
nod conţine un obiect al colecţiei. Arborele este o structură ierarhică. În vârf
există un nod numit rădăcină, de la care pornesc ramurile, către nodurile
nivelului inferior. Nodurile terminale se numesc frunze.
Arborele binar este un caz particular în care fiecare nod posedă cel mult
două ramuri către nodurile nivelului inferior.
Implementarea în memorie a unui arbore se poate realiza cu ajutorul
pointerilor. Fiecărui nod îi corespunde un ansamblu de cuvinte de memorie
care conţin datele şi pointerii reprezentând ramurile care pleacă din nod.

Cozi
O coadă este un fir de aşteptare (FIFO = First In First Out). Inserările se
realizează la o extremitate iar extragerile se fac la celălalt capăt. Realizarea
este posibilă cu ajutorul unui vector şi a doi pointeri.
Pentru a evita deplasarea cozii în memorie, se poate defini o zonă de
memorie circulară, adică prima adresă să urmeze după ultima adresă. Un
pointer pointează asupra ultimului element din coadă, unde se adaugă datele,
iar al doilea pointer indică primul element, unde se extrag datele.

Stive
O sivă LIFO = Last In First Out este o structură liniară particulară, în
care datele sunt adăugate sau extrase la o extremitate predeterminată.
Stiva este una dintre structurile cele mai importante şi mai utilizate (de
exemplu: recursivitate, întreruperi multinivel, maşină pe 0 adrese etc.).

107
Implementarea în memorie a unei stive se poate face cu ajutorul unui
vector şi a unui pointer care indică vârful stivei, unde datele sunt depuse sau
de unde sunt extrase.
Tabele
În capitolul precedent am descris tabelele utilizate de asamblor şi
compilator pentru păstrarea simbolurilor şi valorilor corespunzătoare.
Se poate defini o tabelă ca o structură în general neordonată de date de
acelaşi tip, unde fiecare dată are asociată o informaţie unică numită cheie şi
care serveşte la identificarea elementului tabelei. De exemplu, dacă vom
considera o agendă telefonică, cheia este numele abonatului iar informaţiile
asociate pot fi adresa şi numărul de telefon.
Căutarea unui element în tabelă se realizează prin specificarea cheii.
Deşi au fost elaborate mai multe metode de căutare în tabele, nu există o
tehnică universală şi optimală, alegerea depinzând de tipul şi talia tabelei,
precum şi de specificul utilizării sale.
Vom prezenta trei algoritmi de căutare în tabele utilizaţi frecvent în
programare: căutarea liniară, căutarea binară şi adresajul dispersat.

Căutarea liniară
Tabelele de simboluri, construite în timpul primei treceri ale unui
asamblor şi în timpul fazelor de analiză lexicală şi sintactică ale unui
compilator, asociază numele simbolic al unei variabile sau al unui
identificator oarecare utilizat drept cheie a tabelei un anumit număr de
atribute, ca de exemplu: tip, adresă, protecţie, etc. Atunci când traducătorul
întâlneşte un simbol, el trebuie să verifice dacă există deja în tabelă, altfel
trebuie să stabilească o nouă intrare în tabelă.
Deoarece nici simbolurile şi nici ordinea de prezentare nu sunt
cunoscute în prealabil, traducătorul introduce datele în tabelă, pe măsură ce
întâlneşte noi simboluri în programul sursă, deci tabela este nesortată.
Pentru a găsi un element în tabelă se poate utiliza metoda de căutare
liniară. Este cea mai simplă metodă, dar şi cea mai puţin performantă. Ea
constă în a parcurge tabela începând cu primul element şi comparând fiecare
nume cu cheia de căutare. Cu o tabelă de n elemente, timpul mediu de
căutare este proporţional cu n / 2.
Dezavantajul unei astfel de metode este deci numărul mare de
comparaţii. Avantajele se referă la uşurinţa de realizare, aplicarea ei pentru
tabele nesortate (sortarea unei tabele ia mult timp) şi faptul că pot fi
efectuate căutări în timpul încărcării tabelei.

108
Căutarea binară
Printre tehnicile rapide, dar care impun existenţa unei tabele ordonate,
se poate cita căutarea binară sau dihotomică binary search.
Ideea constă în a considera cheile ca fiind uniform distribuite şi deci de a
începe căutarea prin compararea cheii date cu cea plasată în mijlocul tabelei.
Această comparare permite eliminarea dintr-o dată a unei jumătăţi a tabelei. Se
poate continua în acelaşi mod aplicând metoda pentru elementele rămase
ş.a.m.d. Metoda converge rapid şi durata căutării este proporţională cu log2(n).
Figura următoare prezintă comparativ cele două căutări şi se observă că
metoda de căutare liniară necesită 13 comparări în timp ce metoda
comparării binare necesită doar 4 comparări ale cheii (caută: mmmmm).
Căutare liniară Căutare binară
Tabela nesortată Tabela sortată

1  ccccc aaaaaa

2  ggggg bbbbb

3  zzzzz ccccc

4  sssss ddddd

5  eeeee eeeee

6  hhhhh fffff

7  kkkkk ggggg

8  lllll hhhhh

9  qqqqq iiiii

10  aaaaa jjjjj  1

11  ddddd kkkkk

12  fffff lllll  3

13  wwwww mmmmm  4

14  mmmmm nnnnn

ooooo ooooo  2

ttttt ppppp

bbbbb qqqqq

109
rrrrr rrrrr

uuuuu sssss
Avantajul acestei tehnici provine din numărul redus de comparaţii
necesare pentru a găsi obiectul dorit. Pentru o tabelă cu 1000 de date,
căutarea binară va putea găsi orice cheie din 10 comparări, în timp ce
căutarea liniară ar necesita în medie 500 de comparări.

Adresaj dispersat
O soluţie ideală ar fi ca să existe un mecanism de căutare rapidă care să
nu impună ca tabela să fie ordonată. Memoriile asociative realizează o
căutare paralelă pe toate cheile, dar o memorie asociativă de mare capacitate
este costisitoare. Pentru simularea comportamentului unei memorii
asociative (acces aleator) se poate utiliza metoda de adresaj dispersat
(hashing, hash code).
Această tehnică foarte utilizată constă în evidenţierea unei funcţii de
hashcode, care se aplică cheii şi furnizează o adresă sau un indice în tabela
asociată. Funcţia de hashcode este importantă, ea trebuie să furnizeze adrese
destul de uniform distribuite în intervalul de adrese disponibile.
Dacă aplicarea funcţiei de hashcode asupra a două nume de simboluri
alese drept cheie dă acelaşi rezultat, adică cele două obiecte ar trebui să fie
plasate la aceeaşi adresă, spunem că s-a realizat o coliziune. O bună funcţie
de hashcode trebuie să genereze un număr minim de coliziuni.
Este foarte clar că spaţiul de adrese din cadrul tabelei trebuie să fie
suficient pentru a conţine toate obiectele.
Pentru rezolvarea coliziunilor se pot utiliza mai multe strategii:
- liste înlănţuite pentru adresarea obiectelor implicate, fiecare listă să
înceapă la adresa comună;
- repetarea calculului de adresă cu o a doua funcţie de hashcode;
- plasarea obiectului care găseşte locul ocupat la adresa următoare
sau la prima adresă disponibilă (presupune o tabelă generos
dimensionată, şi în plus o căutare liniară).
Metoda adresajului dispersat permite stabilirea unei relaţii funcţionale
cheie-adresă, de aceea căutarea în tabele se limitează la o singură comparare
(exceptând coliziunile) după calculul adresei cu ajutorul funcţiei de
hashcode.

6.2 Fişiere şi de baze de date

110
Structurile de date prezentate sunt adaptate organizării memoriei
centrale, adresabile prin cuvinte sau octeţi.
Fişierele sunt o structură adaptată memoriilor auxiliare (unităţi de bandă
şi discuri magnetice).
Un fişier este o colecţie de date reprezentând o entitate pentru utilizator.
În mediul informatic, datele unui fişier sunt înregistrate astfel încât să fie
facilitată citirea şi prelucrarea acestora cu calculatorul. În acest context, un
fişier este deci o colecţie de date, rezultate, un text, un program sursă, un
program binar executabil etc. Un fişier este conceput ca o colecţie de
înregistrări. Prezentarea detaliată a conceptului de fişier va fi realizată în
capitolul următor.
O bază de date este un ansamblu structurat de date. Conţinutul unei
baze de date este cunoscut sub numele de bancă de date.
O bază de date permite regruparea şi centralizarea informaţiilor
necesare diverselor aplicaţii în vederea unei mai bune repartizări.
Din punct de vedere logic, o bază de date (BD) data base este
constituită din mulţimea informaţiilor relative la un subiect dat. Această
mulţime trebuie să respecte următoarele criterii:
- exhaustiviate : informaţii complete despre un subiect dat;
- neredondanţă : unicitatea informaţiilor în baza de date;
- structură : asigură o bună gestionare a bazei de date.
Din punct de vedere fizic, o bază de date este o virtualizare a noţiunii de
fişier. În general, bazele de date sunt stocate pe discuri magnetice şi gestiunea
lor se efectuează direct asupra discurilor. O bază de date este implementată cu
fişiere dar acest aspect nu este transparent pentru utilizatori. Stocajul fizic al
unei baze de date constă într-o mulţime de înregistrări fizice organizate cu
ajutorul listelor, pointerilor şi diverselor metode de indexare.
Operaţiile care se pot efectua asupra unei baze de date sunt :
- interogare sau consultare;
- actualizare;
- inserare;
- suprimare.
Pentru efectuarea acestor operaţii sunt necesare programe adecvate,
reunite sub denumirea de Sistem de gestiune de baze de date (SGBD)
DBMS : DataBase Management System.
Un aspect important al bazelor de date actuale este independenţa datelor
faţă de aplicaţii, ceea ce constituie principalul obiectiv al bazelor de date. În
vederea asigurării unei accesibilităţi sporite a informaţiilor se realizează o
separare între problemele de stocaj şi întreţinere, pe de o parte, şi

111
problemele de prelucrare ale utilizatorilor, pe de altă parte, realizându-se
astfel o independenţă între date şi metodele de acces.
Pentru simplificarea problemelor de acces s-au elaboart mai multe
modele logice de baze de date: modelul ierarhic, modelul reţea, modelul
relaţional şi modelul pe obiecte.
Modelul ierarhic constă în organizarea datelor de manieră
arborescentă, ceea ce constituie o structură simplă care este o ierarhie în care
fiecare element nu are decât un superior, fără a exista conexiuni între
ramurile de pe acelaşi nivel.
Modelul reţea este o extensie a modelului precedent deoarece permite
stabilirea conexiunilor între elemente diferite. În acest mod se poate realiza
un mare număr de interogări posibile, dar acestea trebuiesc prevăzute la
construirea bazei de date. În această clasă de SGBD, modelul CODASYL
este unul din cele mai răspândite.
Modelul relaţional (de exemplu: SGBD Ingres, SQL/DS, Oracle,
Informix, Access etc.) permite eliminarea constrângerii de cunoaştere în
avans a interogărilor care se vor efectua, permiţând stabilirea conexiunilor în
momentul execuţiei.
Datele sunt stocate sub formă de relaţii în tabele, iar accesul la
informaţii se efectuează prin aplicarea celor trei operaţii de bază: selecţia,
proiecţia, compunerea.
Selecţia constă în extragerea dintr-o relaţie a acelor elemente care
satisfac o condiţie.
Proiecţia permite izolarea unui număr de coloane dorite.
Compunerea produce noi tabele pornind de la tabele existente.
Bazele de date permit definirea unei structuri logice deasupra structurii
fizice (cea de fişiere pe disc) care nu este adaptată manipulării datelor.
Interfaţa dintre o aplicaţie şi o bază de date este efectuată cu ajutorul
limbajelor specifice, dintre care cel mai cunoscut este SQL. Limbajul SQL
Structured Query Language este un limbaj standard de definire şi
manipulare a datelor din bazele de date relaţionale.
Modelul pe obiecte este un sistem de baze de date orientate obiect
OODB-Object Oriented DataBases. Principiul acestui nou model este
relativ simplu, el constă în a utiliza aceleaşi structuri de date în aplicaţie şi în
baza de date, realizând astfel o corespondenţă directă între aplicaţie şi baza
de date.
Aceste structuri de date sunt clase de obiecte şi baza de date este o bază
de obiecte. Obiectele bazei de date sunt obiecte persistente şi care
beneficiază de polimorfism şi moştenire ceea ce garantează o bună
flexibilitate.

112
Conceptul de obiect a dat naştere unei noi tehnologii care se aplică în
numeroase domenii, de exemplu: limbajele de programare, sistemele de
operare şi bazele de date.

7 SISTEME DE OPERARE

Un sistem de calcul fără software-ul său este inutil. Software-ul


exploatează universalitatea sistemului, asigurându-i potenţialul necesar
rezolvării problemelor. Sistemul de calcul, prin intermediul software-ului
său, poate de exemplu, să faciliteze scrierea unei scrisori, să recunoască
forme, să prevadă timpul, să stocheze sau să imprime imagini, să corecteze
erori de ortografie, să realizeze simplificarea unei expresii algebrice,
optimizarea concepţiei unui circuit electronic etc.
De-a lungul timpului software-urile au evoluat în mai multe direcţii:
a) software-uri de aplicaţie, care servesc la rezolvarea unor probleme
specifice, pot fi scrise de utilizator, sau sunt elaborate de către firme
specializate, cum este cazul programelor de utilitate generală:
procesoare de texte, software-uri de gestiune şi contabilitate, pentru
concepţia asistată de calculator, didactice etc.
b) software-uri utilitare, care oferă ajutor pentru dezvoltarea
aplicaţiilor, cum ar fi: compilatoarele, asambloarele, linkeditoarele,
programele încărcătoare şi depanatoare etc. cuprinzând de asemenea
instrumente grafice şi de comunicare.
Sistemul de operare operating sistem este un produs software care
coordonează ansamblul tuturor activităţilor sistemului de calcul, asigură
gestiunea eficientă a resurselor sale şi facilitează munca utilizatorilor prin
preluarea unor sarcini complicate cum ar fi, de exemplu, controlul
perifericelor sau stocarea şi gestiunea fişierelor.
Sistemul de operare permite interacţiunea directă între om şi sistemul de
calcul, oferind în acest sens o interfaţă convenabilă şi organizând prelucrarea
şi stocarea programelor şi datelor.
Sarcinile sistemelor de operare s-au amplificat de-a lungul timpului şi
astfel, volumul său a crescut considerabil, necesitând eforturi deosebite pentru
programare. Un sistem de operare modern este constituit din sute de mii, chiar
milioane de instrucţiuni, solicitând utilizarea limbajelor de programare
evoluate adaptate scrierii acestui gen de software. Pentru a reliefa importanţa

113
deosebită a sistemului de operare, în lumea informaticii se spune că „un
elefant este un şoricel împreună cu sistemul său de operare”.

7.1 Evoluţie şi caracteristici

Calculatoarele primei generaţii erau lipsite de sistem de operare, erau


programate în binar, programele erau încărcate în memorie, executate şi puse
la punct de la pupitrul de comandă.
Chiar şi după apariţia limbajului de asamblare procedura de utilizare a
sistemului de calcul era aceeaşi, utilizatorul era stăpân unic asupra maşinii
pe toată durata de execuţie a programului său care putea să fie foarte mare.
Etapele evoluţiei unui sistem de operare corespund introducerii unor noi
dispozitive capabile să amelioreze performanţele sistemului de calcul.
Evoluţia sistemelor de operare cuprinde următoarele etape:
a) Monitorul sau executivul anilor ‘60 este precursorul sistemelor de
operare moderne. El este un program însărcinat cu asigurarea bunei
desfăşurări a operaţiilor prin secvenţializarea acţiunilor utilizatorilor
şi asigurarea continuitatea operaţiilor;
b) Sisteme pe loturi sau trenuri de lucrări batch, sunt sisteme
monoutilizator apărute la sfârşitul anilor ‘50, o dată cu introducerea
primelor sisteme pe tranzistoare şi dotate cu benzi magnetice, care
asigurau succesiunea mai rapidă a informaţiilor. Programarea era în plin
avânt datorită apariţiei limbajului Fortran. Separarea operaţiilor de
intrare/ieşire de cele de prelucrare se realizează prin utilizarea unui
calculator auxiliar. Joburile, prezentate operatorului sub formă de
pachete de cartele perforate sunt recopiate pe bandă magnetică de către
calculatorul auxiliar. Banda, conţinând un lot de lucrări se constituie ca
intrare pentru calculatorul principal care execută acţiunile în ordinea
prezentării, iar rezultatele se scriu de asemenea pe bandă pentru a putea
fi imprimate în continuare de către calculatorul auxiliar;
c) Independenţa intrărilor/ieşirilor este un deziderat de la mijlocul anilor
‘50, care se materializează prin realizarea următoarelor dispozitive:
 unităţi de discuri şi tambururi magnetice la un preţ abordabil,
care oferă un acces aleator şi capacităţi de memorare importante;
 unităţi de canal şi sistemul de întreruperi, care elimină
dependenţa intrărilor/ieşirilor de prelucrări;
Joburile sunt citite şi stocate pe disc în fişiere (spooling), şi sunt
utilizate de către monitor în momentul execuţiei, acesta putând
alege ordinea de execuţie pe baza unor criterii de exploatare care se
prezintă sub forma unui sistem de priorităţi. Monitorul este dotat în

114
acest sens cu un nou modul, planificatorul scheduler, care
asigură planificarea lucrului.
d) Multiprogramarea. Un sistem de calcul este multiprogramat dacă
mai multe programe sunt încărcate în memorie în scopul partajării
CPU-ului, asigurându-se exploatarea mai eficientă a sistemului de
calcul prin eliminarea perioadei de aşteptare a unităţilor de prelucrare
în timpul operaţiilor de intrare/ieşire. Sistemul de operare va conţine
un nou modul, alocatorul, care asigură gestiunea CPU ţinând cont de
sistemul de priorităţi gestionat de către planificator, dar poate decide
de asemenea întreruperea unei execuţii prelungite fără să aştepte o
operaţie de intrare-ieşire în vederea unei partajări echitabile a CPU-
ului. Multiprogramarea ridică o serie de probleme:
 partajarea unităţii de prelucrare între programe şi salvarea
contextului (starea de execuţie) pentru fiecare program;
 gestiunea memoriei centrale încât să permită încărcarea unui
număr ridicat de programe într-un spaţiu limitat;
 gestiunea intrărilor/ieşirilor pentru diversele programe, asigurând
transferul de date între memorie şi unităţile periferice şi împiedicând
sistemul să „amestece” informaţiile specifice programelor;
 protejarea programelor şi a datelor stocate în memoria centrală
şi pe disc, eventualele erori putând avea consecinţe grave
asupra derulării operaţiilor;
e) Sistemele în timp partajat time-sharing, numite de asemenea
multiacces sau multiutilizator, sunt o variantă a sistemelor
multiprogramate în care timpul CPU este distribuit în mici tranşe egale
unui mare număr de utilizatori interactivi, conectaţi la sistem. Sistemele
actuale combină prelucrările batch şi time-sharing. Într-un sistem în timp
partajat, orice job lansat de la un terminal poate fi direct controlat de
către utilizator, care are posibilitatea, de exemplu, să decidă corectarea
erorilor, recompilarea şi relansarea în execuţie. Acest mod de exploatare
este adaptat în special fazei de punere la punct a unui program, în timp ce
modul batch este utilizat în general pentru aplicaţii care vizează activităţi
de producţie şi pentru alte sarcini interactive.
Caracteristicile sistemelor de operare pentru sistemele
multiprogramate vizează următoarele aspecte:
a) Exploatarea resurselor este o sarcină fundamentală care asigură:
 paralelismul între diverse activităţi în vederea creşterii
performanţelor sistemului de calcul. Noţiunea de procese
paralele şi concurente facilitează înţelegerea funcţionării unui
sistem de calcul multiprogramat;

115
 partajarea resurselor şi a informaţiilor este asigurată prin
gestiunea diferitelor unităţi funcţionale ale sistemului (CPU,
memorie centrală şi auxiliară, dispozitive de intrare/ieşire),
permiţând acccesul simultan la datele comune (baze de date,
fişiere etc.) şi la anumite programe (utilitare, biblioteci etc.);
 interdependenţa între funcţiunile sistemului de operare şi
alte funcţiuni, deoarece nu există o distincţie netă între ele, de
exemplu, compilatorul şi editorul de texte sunt considerate
programe utilitare, iar în sistemul Unix, modulul de gestiune a
fişierelor este tratat ca o aplicaţie oarecare;
 nedeterminismul operaţiilor care vizează caracteristica de
comportament a sistemelor de operare. Dacă la nivelul unei aplicaţii,
execuţii repetate cu aceleaşi date produc aceleaşi rezultate, sistemul
de operare trebuie să reacţioneze la situaţii nereproductibile, la
evenimente aleatoare, ca de exemplu, întreruperi generate de
dispozitive de intrare/ieşire, transferuri de date repetate ca urmare a
erorilor detectate în urma verificărilor de paritate etc.
b) Virtualizarea sistemului prezintă utilizatorului, prin intermediul
limbajului de comandă, o maşină virtuală mai uşor de programat
decât cea reală. Limbajul de comandă furnizează modalitatea de a
comunica sistemului, prin formularea de cereri, toate informaţiile
necesare diferitelor etape de lucru. Deşi există o oarecare asemănare
între limbajele de comandă şi cele de programare în sensul
formulării unor fraze care specifică într-un mod neambiguu acţiuni
de executat, totuşi, instrucţiunile unui limbaj evoluat de programare
sunt în mod normal executate de către CPU după ce au fost traduse
de către compilator, în timp ce comenzile unui limbaj de comandă
sunt interpretate de către sistemul de operare. Maşina virtuală
„ascunde” utilizatorului toate detaliile privind, de exemplu, o
operaţie de intrare/ieşire sau o manipulare de fişiere;
c) Dispozitivele esenţiale pentru sisteme multiprogramate, ca de
exemplu, canale de intrare/ieşire, sistemul de întreruperi, memoriile
auxiliare şi terminalele interactive, la care se adaugă alte dispozitive
pentru protecţia programelor şi a datelor, pentru relocarea dinamică
a programelor sau pentru gestiunea memoriei virtuale stau la baza
oricărui sistem de operare modern;
d) Maşină cu două stări:
 starea supervizor, rezervată sistemului de operare;
 starea utilizator, în care intră programele de aplicaţie.

116
Această concepţie permite dotarea sistemului cu un set instrucţiuni
de bază, executabile în cele două stări, şi câteva instrucţiuni
suplimentare, instrucţiuni privilegiate, executabile numai în mod
supervizor. Starea sistemului este specificată prin poziţionarea unui
indicator accesibil pentru modificare doar sistemului de operare (de
exemplu, un bit al registrului de stare). În anumite situaţii,
indicatorul de stare trece automat în starea supervizor, de exemplu
în cazul unei întreruperi sau în caz de eroare, sau în general, ca
urmare a unui eveniment care necesită intervenţia sistemului.
Interfaţa între cele două stări este asigurată prin existenţa unei
instrucţiuni neprivilegiate, numită cerere a supervizorului.
e) Program, procesor, proces. Un program este o secvenţă statică de
instrucţiuni. Un procesor execută instrucţiunile unui program. Un proces
este o acţiune, o secvenţă de operaţii care se derulează pentru realizarea
unei sarcini determinate, pe scurt, este un program în execuţie.

7.2 Structura unui sistem de operare modern

Examinând funcţiunile unui sistem de operare modern, se poate aprecia


că acesta se bazează pe un model structurat pe nivele, de exemplu, sistemul
de gestiune a fişierelor face apel la sistemul de gestiune a intrărilor/ieşirilor,
care la rândul său, utilizează modulul de prelucrare a întreruperilor etc.
Se poate realiza un model de sistem de operare bazat pe o suprapunere de
nivele funcţionale, nivelele inferioare fiind în interacţiune directă cu hardware-
ul, iar cele superioare servesc interfeţei cu utilizatorul. Fiecare nivel utilizează
funcţiuni definite de către nivelele inferioare, iar această abordare este
asemănătoare cu cea adoptată pentru definirea nivelelor funcţionale privind
protocoalele de comunicare într-o reţea de calculatoare (modelul ISO-OSI).
Figura următoare prezintă structura unui sistem de operare conform modelului
expus, din care se desprinde ideea complexităţii sistemului de operare.
utilizatori
programe de
interfaţă utilizator aplicaţie ale
interpretor de comenzi utilizatorilor
şi
planificarea lucrului programe de
servicii
gestiunea fişierelor - compilatoare
- linkeditoare
gestiunea intrărilor/ieşirilor - editor de texte

117
....
gestiunea memoriei centrale

nucleu sistem de operare

gestiunea gestiunea gestiunea


proceselor întreruperilor CPU

hardware
Nucleul sistemului de operare
Funcţiunile principale ale nucleului kernel sunt următoarele:
a) alocarea CPU;
b) gestiunea întreruperilor;
c) gestiunea proceselor.
Nucleul este singura componentă a SO în întregime rezidentă în memoria
centrală. Funcţiunile sale implică intervenţii frecvente şi rapide. De aceea, şi
datorită ocupării permanente a unei părţi din memorie, codificarea nucleului
trebuie realizată cu mare atenţie şi optimizată.
Este într-adevăr nivelul cel mai solicitat al sistemului, codificat adesea în
limbaj de asamblare, restul sistemului fiind codificat în limbaj de
programare evoluat orientat sistem (C, Pascal concurent, Modula-2).

Alocare CPU
Alocatorul (dispecerul) este responsabil cu repartizarea timpului
disponibil unităţii de prelucrare (sau unităţilor de prelucrare în cazul
arhitecturilor multiprocesor) între diferite procese.
Sarcina sa implică gestiunea unui fir de aşteptare, unde procesele care
sunt gata să utilizeze CPU sunt clasate în ordinea priorităţii. Prioritatea
este atribuită de planificator în funcţie de urgenţa prelucrării şi resursele
solicitate şi este modificată dinamic pe baza timpului de aşteptare între două
execuţii parţiale. Dispecerul alocă CPU procesului care se găseşte în capul
cozii în momentul în care CPU devine disponibil.
Dispecerul trebuie de asemenea să salveze starea (contextul) procesului a
cărui execuţie s-a întrerupt şi trebuie să furnizeze CPU-ului elementele de
context (echipament) ale procesului desemnat ca succesor.
Pentru salvarea informaţiilor privind starea proceselor, se asociază
fiecărui proces o zonă de memorie conţinând toate informaţiile esenţiale ca:
identificator, paritate, context, statut (de exemplu activ, dacă este stăpân al
CPU; gata de execuţie, dacă este încărcat în memorie şi dispune de toate
resursele, fără CPU; în aşteptare, dacă este pe disc în aşteptarea posesiei

118
perifericelor şi spaţiului de memorie necesare; suspendat, dacă execuţia sa a
fost întreruptă; terminat, dacă procesul şi-a realizat sarcinile şi execuţia sa a
luat sfârşit), necesităţile în resurse etc.
Acest bloc de informaţii se numeşte vector de stare, sau descriptor, sau
imaginea procesului. Aceşti descriptori sunt regrupaţi într-o structură de
date şi pot fi accesaţi printr-un pointer pornind de la o tabelă centrală.
Această structură este accesibilă programelor nucleului.
Dispecerul este solicitat în toate cazurile în care trebuie schimbat
procesul stăpân al CPU. De exemplu când procesul executant declanşează o
operaţie de intrare/ieşire, sau când o întrerupere de ceas semnalează că
tranşa de timp alocată este epuizată şi trebuie suspendată execuţia, atunci
trebuie atribuit CPU unui alt proces.
Dispecerul va fi de asemenea activ când o întrerupere externă modifică
starea procesului stăpân al CPU, sau îl face pe moment inoperant (de
exemplu tratarea unei erori).

Gestiunea proceselor
Un proces (task) este un calcul care poate fi executat concurent sau în
paralel cu alte calcule. El este o abstractizare a procesorului, fiind considerat
ca un program în execuţie.
Existenţa unui proces este condiţionată de existenţa a trei factori:
a) o procedură (un set de instrucţiuni) care trebuie executată;
b) un procesor care să poată executa aceste instrucţiuni;
c) un mediu (memorie, periferice) asupra căruia să acţioneze
procesorul conform celor precizate în procedură.

Programare paralelă şi concurentă


Caracteristic programării paralele este faptul că procesele paralele nu
sunt condiţionate unul de celălalt, nu colaborează între ele, execuţia unuia nu
este în nici un moment dependentă de rezultatele parţiale ale celuilalt.
Spunem că avem de-a face cu programare concurentă atunci când
procesele paralele se intercondiţionează reciproc.
Într-un sistem de calcul, paralelismul proceselor trebuie înţeles astfel:
Dacă Ii şi Ij sunt momentele de început a două procese Pi şi Pj, iar Hi şi Hj
sunt momentele lor de sfârşit, Pi şi Pj sunt executate concurent dacă max (Ii ,
Ij) min (Hi , Hj).

Definiţia 7.1 Execuţie paralelă


Despre două instrucţiuni succesive S1 şi S2 spunem că pot fi executate în
paralel, dacă efectul lor asupra mediului este acelaşi, indiferent dacă mai

119
întâi se execută complet S1 şi apoi S2, sau se execută complet S2 şi apoi S1,
sau execuţia uneia începe înaintea terminării execuţiei celeilalte.

Exemplul 1: Un program citeşte de la două periferice diferite pe a şi b,


după care tipăreşte suma lor c. S1 şi S2 se pot executa în paralel.
S1: read (a);
S2: read (b);
S3: c : a+b;
S4: write (c);
Definiţia 7.2 Graf de precedenţă
Un graf aciclic (X, U) este graf de precedenţă asociat unui program,
dacă X este mulţimea instrucţiunilor programului, iar mulţimea arcelor U
este formată din perechi (Si, Sj) pentru care Si precede Sj.

Exemple de grafuri de precedenţă şi neprecedenţă:

S1 S2 S1 S1

S3 S2 S3

S4 S4 S2

S5 S6
S7 S3
Grafuri de precedenţă Graf de neprecedenţă

Condiţii de paralelism
Notăm R (Si) a1, a2, ..., am mulţimea tuturor variabilelor referite în
instrucţiunea Si fără a fi modificate;
Notăm W (Si) b1, b2, ..., bn mulţimea tuturor variabilelor referite şi
modificate în instrucţiunea Si;

Teorema 5.1 (Bernstein)


Două instrucţiuni S1 şi S2 se pot executa în paralel dacă şi numai dacă:
a) R (S1)  W (S2)  ;
b) W (S1)  R (S2)  ;
c) W (S1)  W (S2)  ;

120
În cazul grafurilor de precedenţă prezentate anterior, R (S1)  ; R
(S2)  ; W (S1)  a; W (S2)  b, deci concurenţa este posibilă, dar S2
şi S3 nu pot fi executate concurent deoarece W(S2)  W(S3)  a  .

Mecanisme de specificare a concurenţei


Grafurile de precedenţă sunt un model matematic pentru concurenţă, dar
nu pot descrie direct concurenţa în limbajele de programare.

Construcţiile FORK, JOIN, QUIT


Instrucţiunea FORK are sintaxa: FORK etichetă; şi provoacă execuţia
concurentă a două secvenţe de program, deci crează două procese paralele.
Instrucţiunile primului proces încep la eticheta etichetă, iar pentru al doilea
proces instrucţiunile sunt cele care urmează după FORK.
Instrucţiunea JOIN are sintaxa: JOIN nr, etichetă şi are rolul de a
recombina nr procese, toate terminate. După ce a fost executată a nr-a oară,
se trece la instrucţiunea cu eticheta etichetă. Variabila nr indică numărul de
procese paralele care mai sunt de aşteptat în vederea reunirii.
Instrucţiunea QUIT are sintaxa: QUIT şi are ca efect terminarea
procesului care o execută (de obicei însoţeşte pe JOIN).
Prezentăm descrierea FORK-JOIN-QUIT pentru grafurile de
precedenţă din figura anterioară:
nr : 2; S1;
FORK L1; nr : 3;
read(a); FORK L1;
goto L2; S2;
L1: read (b); S4;
L2: JOIN nr, L3; FORK L2;
QUIT; S5;
L3: c: a+b; goto L3;
write (c) L2: S6;
goto L3;
L1: S3;
L3: JOIN nr, L4;
QUIT;
L7: S7;

Mecanismul PARBEGIN-PAREND
O astfel de construcţie are forma: S0; PARBEGIN S1 S2...Sn
PAREND; Sn+1; şi corespunde grafului de precedenţă următor:

121
S0

S1 S2 ... Sn

Sn+1
Deci instrucţiunile S1, S2, ..., Sn sunt lansate în execuţie simultan şi sunt
executate concurent. Prezentăm descrierea grafurilor de precedenţă din
figura anterioară cu PARBEGIN-PAREND.
S1:
PARBEGIN
begin
PARBEGIN S2;
read (a); S4;
read (b); PARBEGIN
PAREND S5;
c := a+ b; S6;
write (c); PAREND
end;
S3;
PAREND
S7;
Prezentăm în continuare un exemplu de copiere a unui fişier F într-un
fişier G, situat pe un suport diferit, folosind instrucţiuni concurente:
Type articol  record . . . end;
Var F, G: file of articol;
w, r: articol;
begin
reset (F);
rewrite (G);
read (F, r);
while not eof (F) do begin
w:r;
PARBEGIN
read (F, r); | write (G, w);
PAREND;
end;

122
write (G,r);
close (F);
close (G);
end.

Conceptul de semafor
Un semafor s este o pereche (v (s), c (s)), unde v (s) este valoarea
semaforului (valoarea iniţială v0 (s)), iar c (s) o coadă de aşteptare care
conţine pointeri la procesele care aşteaptă la semaforul s. Pentru gestiunea
semafoarelor se definesc două operaţii primitive: WAIT şi SIGNAL.

WAIT(s) apelat de procesul A : SIGNAL(s) apelat de procesul A:


v (s):v (s) -1; v (s): v (s) + 1;
if v (s) < 0 then begin if v (s) < 0 then begin
Trece A în aşteptare; c (s)  > B;
c(s) <  A; Se extrage din coadă B;
Trece controlul la dispecer; Trece controlul la dispecer;
end end
else else
Se trece controlul la A; Se trece controlul la A;
endif endif

Deci operaţia SIGNAL (s) incrementează semaforul s cu o unitate, iar


WAIT (s) decrementează s cu o unitate dacă s este pozitiv.

Elemente de programare paralelă şi concurentă


Problemele programării paralele se referă la:
a) înţelegerea programului care utilizează această tehnică;
b) depanarea programelor şi demonstrarea corectitudinii;
c) identificarea activităţilor paralelizabile.
Exemplu de calcul al unei rădăcini pentru ecuaţia de gradul al doilea:
x : (-b) + sqrt (b * b - 4 * a * c) / (a * a).
Calculul, efectuat pe o maşină secvenţială comportă 9 operaţii
elementare (să zicem 9 unităţi de timp), iar dacă se dispune de un sistem care
admite prelucrarea paralelă atunci calculul durează 6 unităţi de timp:

1 b*b 1 PARBEGIN
2 4*a r1 : - b
3 (4 * a) * c r2 : b * b
4 (b * b) - (4 * a * c) r3 : 4 * a

123
5 sqrt (b * b - 4 * a * c) r4 : 2 * a
6 -b PAREND
7 (- b) + sqrt (b * b - 4 * a * c) 2 r5 : r3 * c;
8 2*a 3 r5 : r2 - r5;
9 (- b) + sqrt (b*b - 4*a*c)/ (2*a) 4 r5 : sqrt (r5);
5 r5 : r1 + r5
6 x : r5 / r4;
Secţiune critică, resursă critică, excludere mutuală
Problema secţiunii critice constă în aceea că două sau mai multe procese
concurente încearcă să modifice o aceeaşi variabilă, de un număr neprecizat
de ori:

PARBEGIN
P1: . . . v : v + 1; . . .
P2: . . . v : v + 1; . . .
PAREND

Vom spune că porţiunea de program prezentată, v : v + 1 este o secţiune


critică, deoarece nu este permis ca ea să fie executată simultan de cele două
procese. Analog, vom spune că variabila v este o resursă critică, deoarece nu
poate fi accesată simultan de mai multe procese. Procesele P1 şi P2 se exclud
reciproc, deoarece au acces exclusiv la secţiunea şi la resursa critică.
Folosirea semafoarelor rezolvă uşor problema secţiunii critice, fiind
necesar un singur semafor s care se numeşte semafor de excludere mutuală.

var s:semafor;
v0 (s):1;
PARBEGIN
P1: repeat
WAIT (s);
secţiune critică;
SIGNAL (s);
rest program1
until false
P2: repeat
WAIT (s);
secţiune critică;
SIGNAL (s);
rest program2
until false

124
PAREND

Sincronizarea proceselor
Operaţia de sincronizare a două procese se enunţă astfel: Procesul P1 nu poate
trece de un anumit punct A decât după ce procesul P2 ajunge într-un punct B.
Utilizând semafoarele, procesul P1 va aştepta în punctul A, prin operaţia WAIT (s),
până când procesul P2 va efectua în punctul B operaţia SIGNAL (s).
var s:semafor;
v0 (s) : 0;
PARBEGIN
P1: repeat . . . A: WAIT (s); . . . until false;
P2: repeat . . . B: SIGNAL (s) . . . until false;
PAREND

Prezentăm în continuare câteva aplicaţii ale sincronizării proceselor:

Problema producătorului şi consumatorului


Să presupunem că există unul sau mai multe procese numite
producătoare, şi unul sau mai multe procese consumatoare (de exemplu
conceptele de pipe şi spooling). Transmiterea informaţiilor de la producători
la consumatori se efectuează prin intermediul unui buffer cu n intrări.
Problema constă în a dirija cele două tipuri de procese astfel ca:
a) să existe acces exclusiv la buffer (semaforul exclus);
b) consumatorii să aştepte când bufferul este gol (semaforul plin);
c) producătorii să aştepte când bufferul este plin (semaforul gol).
Var plin, gol, exclus: semafor;
v0 (plin) : 0;
v0 (gol) : n;
v0 (exclus) :1;
PARBEGIN
Producător: repeat
produce articol;
WAIT (gol);
WAIT (exclus);
depune articol în buffer;
SIGNAL (exclus);
SIGNAL (plin);
until false;
Consumator: repeat
WAIT (plin);

125
WAIT (exclus);
extrage articol din buffer;
SIGNAL (exclus);
SIGNAL (gol);
consumă articol;
until false
PAREND
Problema impasului
Problema impasului se manifestă în următoarea situaţie când ambele
procese sunt blocate.
var x,y: semafor;
v0 (x) : 1;
v0 (y) : 1;
PARBEGIN
A: . . . WAIT (x); . . . WAIT (y);
B: . . . WAIT (y); . . . WAIT (x);
PAREND

Impasul este o stare foarte gravă care poate duce la blocarea sistemului
de operare sau la distrugerea unor procese.

Modelarea matematică a impasului


Să considerăm n procese şi m tipuri de resurse. Un proces oarecare va fi notat cu
litera i şi i 1, 2, ..., n, iar o resursă oarecare cu litera j, şi j 1, 2, ..., m.
Notăm cu xj cantitatea din resursa j existentă în sistem;
Notăm cu c i, j (t) cantitatea din resursa j cerută de procesul i la momentul t;
Notăm cu a i, j (t) cantitatea din resursa j alocată procesului i la momentul t;
Notăm cu r j (t) cantitatea din resursa j care mai este liberă la momentul t;

Definiţie 5.3 Stare realizabilă


Numim stare realizabilă a alocării resurselor la momentul t, dacă au loc
condiţiile:
c i, j (t)  x j, i, j;
a i, j (t)  c i, j (t), i, j;
a 1, j (t) + a 2, j (t) + ... + a n, j (t)  x j, i, j;

Problemele impasului şi rezolvarea lor


a) Ieşirea din impas se rezolvă de regulă adoptând următoarele strategii:
 reîncărcarea sistemului de operare;
 alegerea unui proces „victimă“ care este distrus;

126
 crearea unui punct de reluare, care este o fotografie a
memoriei pentru procesul „victimă“ şi pentru procesele cu
care colaborează;
b) Detectarea unui impas dacă sistemul posedă un mecanism de
prevenire a impasului (de exemplu, detectarea ciclurilor în graful de
alocare a resurselor);
c) Prevenirea impasului se face prin urnmătoarele metode:
 Metoda 1: „totul sau nimic”. Procesul cere resurse în momentul
încărcării, iar SO întocmeşte graful alocării resurselor;
 Metoda a 2-a: cererea de resurse într-o anumită ordine, prin
numerotarea resurselor;
 Metoda a 3-a: alocare şi suspendare controlată.

Gestiunea întreruperilor
Întreruperile sunt constituite dintr-un ansamblu de rutine, fiecare dintre
ele fiind activată la apariţia unui semnal fizic de întrerupere.
Sarcina modulului de gestiune a întreruperilor este determinarea sursei
întreruperii şi activarea rutinei de serviciu sau de răspuns corespunzătoare.
Am văzut ce este un program în limbaj maşină. Putem presupune că
execuţia unei instrucţiuni maşină nu poate fi întreruptă.
Prin starea unui program la un moment dat, notată prescurtat PSW
Program Status Word înţelegem o pereche formată din:
a) adresa următoarei instrucţiuni de executat;
b) conţinutul registrelor maşină la terminarea ultimei instrucţiuni.
Fiecare sursă posibilă a unei întreruperi are asociată o locaţie fixă de
memorie. În această locaţie se află o adresă care indică locul din memorie la
care se găseşte o secvenţă de instrucţiuni, numită handler, care deserveşte
întreruperea respectivă.
La apariţia semnalului de întrerupere, după ce instrucţiunea maşină în
curs s-a executat, se derulează în această ordine, următoarele activităţi:
a) se salvează într-o zonă de memorie (în stivă, sau o zonă prestabilită)
PSW-ul programului în curs de desfăşurare;
b) se restaurează PSW al handlerului asociat întreruperii;
c) handlerul execută acţiunile necesare deservirii întreruperii;
d) se salvează, numai dacă este necesară corelarea a două acţiuni
succesive ale aceluiaşi handler, PSW al handlerului;
e) se restaurează PSW al programului care a fost întrerupt.
Printre întreruperile care trebuie tratate la acest nivel se includ
întreruperile interne, provocate, de exemplu, de detectarea unei erori sau

127
printr-o acţiune care solicită trecerea în starea supervizor, ca şi toate
întreruperile externe.
Ca exemplu de acţiune care cauzează trecerea în starea supervizor se
poate cita cazul unui utilizator care încearcă să execute o instrucţiune
privilegiată sau caută să acceseze o informaţie protejată etc.
Dacă întreruperea implică o schimbare de alocare a procesorului, acest
modul al nucleului va activa dispecerul.

Gestiunea memoriei centrale


Programele au nevoie de memorie pentru execuţia lor (pentru stocarea
instrucţiunilor şi datelor). Numai instrucţiunile stocate în memoria centrală
pot fi executate de CPU.
Dacă sistemul de calcul (SC) este exploatat în monoprogramare,
problema se reduce la partajarea memoriei între programul de aplicaţie de
executat şi partea sistemului de operare rezidentă în memorie, care ocupă în
mod normal o zonă de adrese pornind de la adresa 0, care se numeşte adesea
partea de jos a memoriei.
Dacă sistemul ocupă zona de adrese de la 0 la N, programul utilizator va avea
la dispoziţie spaţiul de adrese de la N + 1 la extremitatea superioară a memoriei.
Dacă programul utilizator are o talie mai mare decât spaţiul disponibil,
programatorul trebuie să „decupeze” programul în module care să se poată
succede în zona de memorie pusă la dispoziţia lor.
Sistemul nu este în mod obligatoriu stocat în memoria RAM, în anumite
cazuri se preferă utilizarea unei memorii ROM separate, pentru raţiuni de
protecţie şi nevolatilitate.
Memoria centrală este o resursă costisitoare şi deci ea este limitată şi
constituie un element critic al performanţei unui calculator.
Dimensiunea memoriilor a crescut considerabil, o dată cu adoptarea
memoriilor electronice, dar şi cea aprogramelor a urmat aceeaşi tendinţă.

Partiţii cu talie fixă


Ideea cea mai simplă de partiţionare a memoriei ca ea să poată conţine
un număr maxim de programe constă în „decuparea” memoriei fizice
disponibile în partiţii fixe, dar nu obligatoriu de talie identică, fixate la
generarea sistemului.
Aceste partiţii fiind fixate în avans şi o dată pentru totdeauna, alocarea
lor prezintă câteva probleme:
a) trebuie gestionate mai multe cozi de procese în aşteptare, sortând
procesele în funcţie de talia lor;

128
b) se produce o oarecare risipă de memorie, deoarece nu poate fi
prevăzută talia joburilor de executat şi rareori se va găsi un proces a
cărui talie să corespundă unei partiţii prestabilite.

Partiţii cu talie variabilă


Inevitabila risipă de memorie a sistemelor cu partiţii fixe conduce la concepţia
partiţiilor adaptabile taliei programelor, numite partiţii cu talie variabilă.
Dacă unul sau mai multe programe îşi termină execuţia, apar zone de memorie
neocupate, deci ar fi de dorit să se ofere posibilitatea deplasării programelor în
memorie. În acest sens, sistemul, din când în când suspendă execuţia programelor şi
efectuează o compactare a spaţiului de memorie care permite rearanjarea memoriei
rămase şi crearea de spaţiu pentru programele în aşteptare.
Pentru a realiza această operaţie de reaşezare sau compactare este
necesară o tehnică de deplasare corectă a programelor încât acestea să-şi
poată continua execuţia. Această tehnică se numeşte relocare (realocare),
sau translatare dinamică şi este realizată cu ajutorul registrelor de bază şi a
dispozitivului de calcul al adresei efective în momentul execuţiei.
Adresa efectivă = adresa de bază + adresa începutului de program
Relocarea dinamică a spaţiului de adrese poate fi realizată deplasând
programul şi modificând conţinutul registrului de bază asociat, iar execuţia
se va efectua corect, adresele fiind calculate la execuţie, în funcţie de adresa
conţinută în registrul de bază.
Figura următoare ilustrează această idee care rezolvă problema numai în
faza iniţială de încărcare a programelor.

zona sistem zona sistem zona sistem

program A program A program A

program B program C

program C program C program D

program D program D program F

program E program G

program F program F

program G program G

129
Încărcare După un anu- Rearanjare
iniţială  mit timp de  prin relocare
funcţionare dinamică
Translatarea dinamică şi protecţia
În sistemele multiprogramate trebuie protejat fiecare program contra
eventualelor greşeli ale altor programe, greşeli susceptibile de a periclita
execuţia corectă a unui program prin posibilitatea de a pătrunde în zona sa
de memorie.
În principiu, este suficientă verificarea ca orice adresă calculată în timpul
execuţiei unui program să fie internă intervalului de adrese alocate
programului respectiv.
Această verificare se realizează cu ajutorul unui dispozitiv special care
compară adresa efectiv calculată cu adresele extreme ale zonei alocate
programului, stocate în registre „bornă“ sau mărginite (este necesar un
singur registru mărginit, deoarece adresa primei locaţii de memorie este
stocată în registrul de bază).
Pentru a găsi adresa referită se calculează adresa efectivă AE = baza +
dep şi se testează dacă baza  AE  sup.
Numai SO are dreptul să modifice conţinutul registrelor de bază şi al
celor mărginite, ceea ce implică instrucţiuni privilegiate care nu pot fi
executate decât în mod supervizor, iar dacă un program face referire la o
adresă din exteriorul bornelor sale, dispozitivul de verificare generează o
întrerupere alertând SO.
Figura următoare prezintă aceste mecanisme.

memorie
bază baza registru de bază

adresa referită dep deplasament


program în raport cu B

sup sup registru mărginit

130
(lim. superioară)

Pentru relocarea dinamică a memoriei şi partajarea mai multor procese se


utilizează dispozitivele următoare:
a) registru de bază;
b) registru mărginit;
c) dispozitiv de calcul al adresei efective pentru orice referinţă la memorie;
d) dispozitiv de verificare a apartenenţei adresei efective la zona de
memorie a procesului.
Datorită acestor dispozitive, SO poate decide deplasarea unui program şi
poate efectua din când în când o reaşezare a memoriei. Procesele care devin
temporar inactive pot fi puse în aşteptare pe disc şi înlocuite în memorie de
alte procese (swapping).
Principalele limite ale acestei tehnici sunt:
a) timp deloc neglijabil petrecut cu reaşezarea;
b) necesitatea alocării de spaţiu contiguu de memorie.
În evoluţia conceptuală a sistemelor de gestiune a memoriei, etapa
următoare constă în a căuta metode de fragmentare a programelor şi
memoriei, astfel încât un program să poată fi încărcat în zone necontigue de
memorie.

Segmentarea
Segmentarea constă în divizarea unui program în module sau segmente,
fiecare segment corespunzând unei entităţi logice cum ar fi o procedură sau
un bloc de date, independentă de alte segmente.
Sistemul de operare se ocupă de plasarea în memorie a segmentelor
necesare execuţiei programelor gata să utilizeze CPU. Sistemul de operare
trebuie să ştie unde sunt stocate diferitele segmente, şi pentru aceasta el
organizează şi gestionează un ansamblu de tabele de segmente, câte o
tabelă pentru fiecare program, conţinând adresele de încărcare ale
segmentelor programului respectiv.
Adresa este structurată şi conţine 2 câmpuri:
a) numărul segmentului;
b) deplasamentul în cadrul segmentului.

131
Calculul adresei efective este realizat ca de obicei cu ajutorul unui
dispozitiv special, adăugând offsetul adresei de încărcare a segmentului care
este stocat în tabele de segmente.
Protecţia poate fi asigurată la nivelul tabelei de segmente adăugându-i
talia fiecărui segment sau ultima adresă a segmentului.

Memorie
Spaţiul de memorie Tabela de
al programului segmente 50K
(în memorie)
70K
0
Segment 1 Număr Poziţie 95K
20
1 50K
0 120K
Segment 2
25 2 95K 130K

0 145K
Segment 3 3 130K
15 155K

0 4 155K 165K
Segment 4
10

Noţiunea de memorie virtuală


Ideea de memorie virtuală este simplă, elegantă şi constă în a trata
diferenţiat adresele referite prin program (adrese virtuale) şi adresele
memoriei fizice (adrese reale).
Mulţimea adreselor virtuale este independentă de implementarea
programului în memoria fizică, este vorba deci de un spaţiu de memorie
virtual (care nu există), dar poate fi utilizat de către programator ca model de
memorie centrală la dispoziţia sa.
Totul se petrece ca şi când utilizatorul ar avea acces la o memorie având
2n locaţii, n fiind numărul de biţi pentru adresele programului.
132
Acest număr n poate fi mult mai mare decât numărul m care reprezintă
talia memoriei fizice. O tabelă de corespondenţă numită tabelă de pagini
sau topografie de memorie, gestionată de către sistemul de operare pune în
corespondenţă cele două spaţii de adrese, iar un dispozitiv special asigură
transformarea unei adrese virtuale în adresă fizică.
Spaţiul virtual de adrese, care rezultă de regulă din linkeditarea
programului este gestionat de sistemul de operare, care este obligat să
utilizeze memorii auxiliare (discuri, tambururi, memorii de sprijin etc), ca
extensii ale memoriei centrale.
Conceptul de memorie virtuală dezvoltat în perioada anilor ‘60 a făcut
obiectul mai multor proiecte de cercetare, iar cea mai mare parte a
calculatoarele anilor ‘70 erau dotate cu memorie virtuală.
Realizarea conceptului de memorie virtuală se bazează pe tehnica
paginării.

Paginare
Conceptul de paginare constă în a decupa cele două spaţii de adrese în
pagini de aceeaşi talie (1024 sau 2048 cuvinte) şi de a evidenţia un
mecanism de transfer de pagini între memoria virtuală şi cea reală.
În orice moment, un program gata de execuţie va avea plasate în
memorie câteva copii ale paginilor sale virtuale, alese în mod corespunzător
pentru a permite execuţiei sale să avanseze.
Sistemul de operare trebuie să rezolve câteva probleme importante:
a) dacă o anumită pagină se găseşte deja în memorie şi unde;
b) cum se convertesc adresele virtuale ale programului în adrese reale;
c) ce pagină va fi înlocuită pentru a face loc alteia;
d) cum se poate şti dacă pagina evacuată din memorie a fost modificată
şi trebuie deci recopiată în memoria auxiliară.

Tabela paginilor
Tabela paginilor constituie mecanismul esenţial care face să corespundă
fiecărei pagini virtuale o serie de informaţii, actualizate de către sistem. Un
bit indicator specifică prezenţa (sau absenţa) paginii în memoria principală.
Dacă pagina este în memoria principală, numărul paginii reale este
înscris în tabelă.
Un alt bit indică dacă pagina a fost modificată în timpul execuţiei.
Mecanismul de transformare a adreselor este următorul: câmpul de
adresă este divizat în două părţi:
a) numărul de pagină, singurul element care se modifică;
b) poziţia în cadrul paginii.

133
Tabela paginilor conţine de asemenea biţi de protecţie specificând un
anumit nivel al protecţiei (protejare în citire, scriere, execuţie etc.).
Tabela paginilor oferă de asemenea protecţia informaţiilor în sensul
apartenenţei adreselor la domeniul alocat paginii respective.

Paginarea la cerere
Această metodă de gestiune a memoriei constă în încărcarea unei pagini
din memoria virtuală numai dacă ea a fost referită.
Spaţiul de lucru
O alternativă a paginării la cerere constă în a plasa în memorie a unui
mic număr de pagini oportun selecţionate, acest ansamblu de pagini
numindu-se spaţiu de lucru.

Paginare şi segmentare
Anumite arhitecturi permit combinarea segmentării cu paginarea. Spaţiul
adreselor virtuale este segmentat şi segmentele sunt decupate în pagini.
Structura adresei trebuie să prevadă atunci trei câmpuri:
a) numărul segmentului ;
b) numărul paginii în cadrul segmentului;
c) deplasamentul în pagină.
Segmentarea fiind o divizare logică a spaţiului de adrese al programului,
este sarcina programatorului să definească segmentele. Paginarea este
realizată prin intermediul hardware-ului şi a sistemului de operare, ea este
deci transparentă pentru utilizator.

Paginarea sistemului de operare


Sistemul de operare este un program chiar dacă el nu este chiar ca toate celelalte
(instrucţiuni privilegiate, mod supervizor etc.), iar cea mai mare parte a sistemului
de operare este supusă paginării, deoarece, datorită taliei sale el nu poate fi stocat în
întregime în memoria principală. Fac excepţie de la această regulă nucleul şi o parte
a programelor de gestiune a memoriei şi intrările/ieşirile.
Programele de serviciu sunt de asemenea paginate. Ca regulă generală,
programele care se execută într-un sistem multiprogramat modern nu au
decât câteva pagini în memoria centrală.
Tendinţele actuale sunt pe de o parte de a trata majoritatea funcţiunilor
sistemului de operare ca procese utilizator şi pe de altă parte de a profita de
microelectronică şi de a încredinţa hardware-ului sau microprogramării
sarcinile frecvente.

Organizarea intrărilor/ieşirilor

134
Intrările/ieşirile constituie domeniul cel mai delicat în concepţia şi
realizarea unui sistem de operare. Importanţa lor este fundamentală, dar
orice generalizare devine dificilă prin varietatea unităţilor periferice şi a
procedurilor de intrare/ieşire utilizate în sistemele de calcul actuale.
Dificultăţile se referă atât la aspectele materiale cât mai ales la
necesitatea de a asigura o gestiune optimală a resurselor sistemului precum şi
simplificarea sarcinii utilizatorilor acestuia.
Iată câteva aspecte ale problemelor care se ridică:
a) diversitatea funcţională a unităţilor periferice: imprimante laser,
unităţi de discuri magnetice şi optice, cartuşe magnetice etc.
b) diferenţa de viteză între unităţile periferice: de la câteva caractere
pe secundă ale tastaturii sau terminalului, la câteva milioane de
caractere într-o secundă pentru o unitate de discuri;
c) diversitatea de codificare şi structurare a informaţiilor
transferate: ASCII, EBCDIC, binar, cuvinte, octeţi, blocuri;
d) diferenţa între metodele de acces ale unităţilor: acces secvenţial
sau aleator, adresaj complet diferit pentru unităţile de bandă, discuri
sau mari memorii de arhivare;
e) diferenţa între condiţiile de partajare a perifericelor: o unitate de
discuri sau ecranul terminalului pot fi utilizate în acelaşi timp de
către mai multe procese, în timp ce o imprimantă nu poate fi
partajată decât în timp şi numai pentru job-uri întregi;
f) marea diversitate a condiţiilor de eroare: eroare de paritate,
imprimantă fără hârtie, eroare de poziţionare a unui cap de
citire/scriere pe disc, unitate deconectată, eroare de adresare etc.;
g) complexitatea sistemelor de legătură între periferice şi unitatea
centrală: DMA, canale, bus, unităţi de comandă, unităţi de
telecomunicaţii etc.;
h) gradul înalt de paralelism al operaţiilor;
i) necesitatea protejării utilizatorilor: „ascunderea” anumitor detalii
legate de operaţiile de intrare/ieşire;
j) necesitatea de a asigura independenţa programelor faţă de tipul
perifericelor utilizate.
Pentru rezolvarea acestor probleme, sistemul de operare încearcă să
trateze toate perifericele de o manieră uniformă (periferice virtuale,
codificare internă a caracterelor etc.), încredinţând toate prelucrările
particulare modulelor specializate, numite gestionari de unităţi periferce
device handlers, drivers.
Ca structură internă, acest nivel al sistemului de operare care se ocupă cu
gestiunea intrărilor/ieşirilor, se poate detalia pe subnivele, astfel:

135
a) proceduri standard (programe de bibliotecă) utilizate de către
aplicaţii şi conţinând cereri către supervizor;
b) un software de intrare/ieşire independent de unităţile periferice;
c) drivere, comandând fiecare unitate în detaliu;
d) programe de serviciu ale întreruperilor, acţionând în colaborare
cu funcţiunile nucleului.
Utilizatorul dispune de un set de instrucţiuni de intrare/ieşire virtuale,
spre deosebire de instrucţiunile de intrare/ieşire în cod maşină, specifice SO.
Instrucţiunile de intrare/ieşire virtuale se prezintă într-un limbaj de
programare evoluat sub forma unui apel de procedură sistem (read, write,
print etc), cu argumentele necesare de apel (nume variabile sau fişier, talie,
format, unitate logică etc.).
Aceste instrucţiuni sun înlocuite prin procedurile sistem corespunzătoare
în timpul fazei de compilare.
Există de asemenea probleme de protecţie la nivelul intrărilor/ieşirilor.
În acest context, sistemul de operare verifică corectitudinea convertirii
adreselor virtuale în adrese reale în momentul iniţializării, împiedicând
modificarea acestora înaintea terminării operaţiei de intrare/ieşire.

Fişiere şi gestiunea fişierelor. SGF.


Gestiunea fişierelor este serviciul cel mai vizibil oferit utilizatorului de
către un sistemul de operare. Cea mai interesantă situaţie apare atunci când
memorarea se face pe suport magnetic, cu accent pe suportul disc, cel mai
convenabil tip de suport magnetic.

Gestiunea fişierelor privită de utilizator


Un volum poate fi o rolă de bandă, un ansamblu formând un disc de
masă, un disc cartuş, un disc flexibil (discheta).
În cadrul unui volum, informaţiile sunt grupate de către SO la indicaţia
utilizatorului în ansambluri distincte numite fişiere.
Utilizatorul are acces prin programele sale la o (mică) entitate din cadrul
unui fişier, cunoscută sub numele de articol. Putem spune că un articol este
o subdiviziune a unui fişier care are un înţeles de sine stătător.
Informaţiile dintr-un articol sunt de regulă grupate în subdiviziuni numite
câmpuri sau atribute. Fiecare câmp sau atribut are în fişier o anumită
valoare. O pereche (atribut, valoare) o vom numi cheie. O cheie unică se
numeşte index de articol.
Lungimea de reprezentare a unui articol poate fi constantă pentru toate
articolele sau poate să varieze de la un articol la altul, deci putem avea
articole de format fix sau variabil.

136
Sistemul de gestiune a fişierelor (SGF) este un ansamblu de rutine de
legătură între utilizatori şi componenta sistemului de intrare/ieşire la nivel
fizic pentru operarea cu fişiere. Utilizatorul dipune de o serie de operaţii
primitive pe care le poate solicita SGF-ului pentru serviciile dorite.

Conceptul de fişier abstract


Se poate defini un fişier ca o funcţie f: N  T, unde N este mulţimea
numerelor naturale iar T mulţimea valorilor posibile pentru un tip de dată
deja definit. Pentru tipurile de date obişnuite (integer, char, real) avem de-
a face cu un fişier obişnuit.
Prin f (i) notăm mulţimea valorilor câmpurilor articolului al i-lea din fişier.
Dacă tipul de dată este la rândul său un tip fişier, avem de-a face cu o
bază de date.
Principalele operaţii asupra unui fişier notat f, presupunând că înaintea
efectuării operaţiei, fişierul are n articole, sunt următoarele:
a) Citirea Read articolului k înseamnă obţinerea valorii f (k);
b) Scrierea Write înseamnă adăugarea unui nou articol la fişier. Deci
fişierul f cu n articole se transformă în fişierul f’ cu n +1 articole
definite astfel:
f’ (i) = f (i) , i 1, 2, ..., n;
f’ (n + 1) = x, unde x este valoarea articolului adăugat.
c) Inserarea Insert unui nou articol cu valoarea x, după articolul cu
numărul de ordine k înseamnă obţinerea unui nou fişier f’ cu n+1
articole:
f’ (i) = f (i) , i 1, 2, ..., k;
f’ (k + 1) = x;
f’ (i + 1) = f (i) , i k+1, ..., n.
Se observă că scrierea este echivalentă cu inserarea la sfârşitul
fişierului iar inserarea după poziţia 0 înseamnă adăugare la
începutul fişierului.
d) Ştergerea Delete articolului k înseamnă obţinerea unui nou fişier f’:
f’ (i) = f (i) , i 1, 2, ..., k - 1;
f’ (i - 1) = f (i) , i k+1, ..., n.
e) Modificarea Modify, Update, Replace articolului k cu un altul de
valoare x înseamnă obţinerea fişierului f’ cu n articole, astfel:
f’ (i) = f (i) , i 1, 2, ..., k - 1;
f’ (k) = x;
f’ (i) = f (i) , i k+1, ..., n.

137
Tipuri de acces la articole
a) Accesul secvenţial la un articol f (i) presupune i - 1 accese în
ordine, la articolele cu numerele de ordine 1, 2, ..., i - 1.
b) Accesul direct random access presupune existenţa unui mecanism
de obţinere a articolului căutat fără a parcurge secvenţial toate
articolele care-l preced. Mecanismul de acces este de două feluri:
 acesul direct prin număr de poziţie (adresă) are loc atunci când i
se furnizează SGF-ului o valoare i şi acesta returnează f (i)
(acces relativ);
 prin conţinut, are loc atunci când i se furnizează SGF-ului o cheie (a,
v) şi acesta returnează acel articol i pentru care f (i). a = v.

Clasificarea fişierelor
a) După lungimea unui articol:
 fişiere cu articole de format fix;
 fişiere cu articole de format variabil.
b) După posibilitatea de afişare sau tipărire:
 fişiere text al căror conţinut poate fi afişat pe ecran sau la
imprimantă;
 fişiere binare, formate din şiruri de octeţi consecutivi, fără
nici-o semnificaţie pentru afişare.
c) După suportul pe care este rezident fişierul
 fişiere pe disc magnetic;
 fişiere pe bandă magnetică;
 fişiere pe imprimantă;
 fişiere tastatură;
 fişiere pe ecran;
 fişiere pe plotter, digitizor;
 fişiere pe cartele perforate;
 fişiere pe bandă de hârtie perforată.
d) După modurile de acces
 fişiere secvenţiale;
 fişiere în acces direct:
i) acces direct prin adresă;
ii) acces direct prin conţinut:
 secvenţial-indexat;
 selectiv;
 multilistă;
 B - arbore;

138
Referirea unui fişier
Utilizatorul se referă la un fişier în conformitate cu anumite reguli
sintactice impuse de către SO. În general, referirea la un fişier se face printr-
un şir de caractere, diferite de spaţiu. Şirul de referinţă conţine 5 zone,
plasate de la stânga la dreapta, astfel:

Periferic : Cale Nume . Tip ; Versiune

Periferic indică numele perifericului suport al fişierului, impus de


sistemul de operare.
Cale desemnează subdirectorul din cadrul discului unde se află fişierul căutat.
Nume este o succesiune de litere şi cifre date de creatorul fişierului.
Tip sau extensie a numelui este dată tot de utilizator şi ea reflectă
conţinutul fişierului.
Versiune este o noţiune specifică unui anumit SO şi diferenţiază mai
multe versiuni ale aceluiaşi fişier.
Acţiunile SGF la nivel de articol
a) citire pentru suporturile disc, bandă magnetică, cartele, tastatură;
b) scriere pentru suporturile disc, bandă magnetică, ecran, imprimantă,
plotter;
c) inserare, ştergere, modificare, pentru suporturile de tip disc.

Acţiunile SGF la nivel de fişier


a) funcţiile de deschidere şi închidere (open, close). Open este operaţia
de deschidere şi conţine acţiunile SGF efectuate înaintea primului
acces la fişier, iar close (închidere) după ultimul acces.
b) alte operaţii globale:
 crearea unui fişier;
 ştergerea unui fişier;
 copierea unui fişier în alt fişier;
 schimbarea numelui unui fişier (redenumire, mutare);
 listarea unui fişier;
 concatenarea mai multor fişiere;
 compararea a două fişiere;
 fuzionarea a două sau mai multe fişiere;
 sortarea (ordonarea) articolelor unui fişier;
 operaţii de filtrare a unui fişier.

139
Descriptorul de fişier este un articol special care conţine informaţiile de
descriere ale unui fişier. Locul său de memorare este în directorul fişierului.
Apar patru grupe de informaţii:
a) identificarea fişierului (N, I), unde N este numele simbolic al
fişierului (specificatorul de fişier fără periferic), iar I este un număr
prin care descriptorul este reperat pe disc) în mod direct;
b) adresele fizice ocupate de fişier;
c) controlul accesului la fişier;
d) informaţii de organizare calendaristice.
Pentru controlul accesului la fişiere se foloseşte matricea de control
unde a (i, j)=1 dacă utilizatorul i are drept de acces la fişierul j, şi 0 în rest.
Clase de utilizatori:
a) proprietar: cel care crează fişierul şi stabileşte drepturi de acces la fişier;
b) utilizatori specificaţi: nominalizaţi de proprietar, cu statut special în
raport cu fişierul;
c) grup sau proiect: care pot folosi împreună un fişier;
d) public: restul utilizatorilor.

Moduri de organizare a fişierelor


a) organizare secvenţială;
b) fişiere în acces direct prin poziţie;
c) fişiere în acces direct prin conţinut;
d) fişiere inverse: pe lângă fişierul de bază se crează automat un fişier
invers care conţine pentru fiecare cheie specificată, adresele disc la
care se află articolele care conţin cheia respectivă. Dacă n1, n2, ..., np
sunt numerele de articole care conţin cheile 1, 2, ..., p, iar aij adresa
articolului j cu cheia i, atunci, dacă j  k, aij  aik i.
e) fişiere multilistă: se definesc atribute şi valori cheie. SGF ataşează
fiecărei chei un pointer către articolul următor care conţine aceeaşi
cheie. Există atâtea liste câte chei sunt. Fiecare articol participă la c
liste, unde c este numărul de scrieri ale articolului, adică numărul de
apariţii ale valorii unei chei. Se crează o zonă cu cheile fişierului şi
adresele primelor articole (fişierul director). Avem că :
 dacă j  k atunci aij  aik i;
 dacă i  k atunci aij  akj , care apare de c ori.
f) fişiere secvenţial-indexate: articolele sunt scrise pe suport în
acces secvenţial şi plasate în ordinea crescătoare a valorilor
indexului, rezultă că se crează o tabelă de indecşi care are o parte
principală şi o parte de depăşire. Există trei nivele pentru tabelele
de indecşi:

140
 nivelul 3: fişier: numărul intrărilor este egal cu cel al
volumelor;
 nivelul 2: volum: numărul intrărilor este egal cu numărul
cilindrilor din cadrul volumului;
 nivelul 1: cilindru, conţine atâtea intrări câte pagini sunt în
cilindrul respectiv.
g) fişiere selective: au funcţia de regăsire materializată printr-un
calcul al CPU, numită funcţie de randomizare f : mulţimea
valorilor posibile pentru index0, 1, ..., n - 1 Articolele care au
aceeaşi valoare pentru funcţie se numesc sinonime.
h) fişiere organizate în B - arbori regulari. Fiecare nod este prevăzut
cu m căsuţe (pentru m chei unice). În fiecare nod pot fi maxim m şi
minim m div 2 chei. Înainte de prima cheie, între 2 chei şi după
ultima cheie sunt pointeri spre noduri subordonate.

Acţiunile SGF la nivel de suport disc


SGF are trei sarcini principale:
a) sistem de regăsire a fişierelor pe disc;
b) evidenţa spaţiului neutilizat pe disc;
c) utilizarea acestui spaţiu pentru crearea sau extinderea fişierelor.

Sisteme de cataloage (directoare)


Sunt tabele care conţin fişierele existente şi informaţii necesare accesului
la aceste fişiere. Fiecare intrare în director conţine un descriptor de fişier.
Principalele operaţii asupra cataloagelor sunt următoarele: căutare, inserare,
ştergere, listare, salvare/restaurare etc.

Integritatea informaţiilor
Deoarece utilizatorul depinde de sistemul de fişiere pentru tot ceea ce
vizează aspecte legate de lucrul cu datele sale, este esenţial ca sistemul să fie
dotat cu mecanisme de salvare a informaţiilor permiţând eventual
reconstituirea fişierelor pierdute într-un accident software sau hardware.
Printre metodele comune utilizate în acest sens, sunt următoarele:
a) salvare completă backup, care permite recopierea pe bandă
magnetică a fişierelor disc, o dată la două sau trei zile. În caz de
accident, se pot reconstitui fişierele care existau în momentul
ultimului backup;
b) salvare incrementală, care permite recopierea doar a informaţiilor
modificate după ultimul backup. Această abordare permite reducerea
frecvenţei backup-urilor masive (de exemplu, o dată pe săptămână

141
sau pe lună). În cazul reconstrucţiei fişierelor, procedurile de lucru
sunt mai complexe;
c) dublarea sistematică a fişierelor disc, care constă în a păstra
întotdeauna două copii ale fiecărui fişier pe două unităţi de disc
diferite. Această metodă necesită mai puţine intervenţii din partea
operatorilor, dar implică dublarea spaţiului disc disponibil.
Servere de fişiere
O abordare modernă a gestiunii fişierelor, foarte la modă datorită
avântului informaticii distribuite, constă în a încredinţa unui calculator
independent întreaga gestiune a fişierelor specifice unei comunităţi de
utilizatori conectaţi la o reţea locală. Un astfel de calculator se numeşte
server de fişiere. În această arhitectură, partea majoră a spaţiului disc este
concentrată în jurul serverului, celelalte calculatoare din reţea nu au nevoie
de capacitate disc locală pentru fişierele lor.
O altă realizare recentă, datorată integrării tot mai pronunţate a
calculatoarelor şi a reţelelor este aceea a dispersate într-o reţea. Utilizatorul
unui astfel de sistem nu ştie şi nu are nevoie să ştie în care calculator sunt
stocate fişierele sale. În momentul în care o cerere de acces este adresată
sistemului de fişiere, acesta determină poziţia fişierului căutat şi, utilizând
serviciile reţelei, pune la dispoziţia solicitantului o copie a fişierului respectiv.

Alocarea resurselor
Într-un mod general, definim o resursă ca fiind un element necesar unui
procesor pentru a asigura execuţia sa în bune condiţiuni.
Resursele materiale ale unui sistem de calcul (CPU, memorii, dispozitive
de intrare/ieşire etc.), sunt disponibile în cantitate limitată şi trebuie să fie
partajate între diferite procese.
Produsele software şi fişierele, dacă pot fi partajate, fac de asemenea
parte dintre resursele pe care sistemul trebuie să le gestioneze.
Mecanismele de alocare ale unei resurse particulare sunt realizate pe
diferitele nivele ale sistemului de operare. De exemplu, dispecerul decide
dacă alocarea CPU şi alocarea unui fişier al unui proces este implementată la
nivelul gestiunii fişierelor.
Strategia de repartizare şi de alocare a resurselor trebuie să fie
determinată global, pentru tot sistemul. La nivelul sistemului, se iau decizii
în legătură cu planificarea globală a activităţii, se decide, de exemplu,
crearea de noi procese, sau aşteptarea, pe baza resurselor disponibile, nivelul
de prioritate al unui job.
Obiectivele acestui nivel al sistemului pot fi rezumate astfel:

142
a) asigurarea unei bune utilizări a resurselor: contabilizarea şi
furnizarea de statistici asupra resurselor principale;
b) crearea de noi procese şi atribuirea unui nivel de prioritate
corespunzător: se permite fiecărui proces existent în sistem să
obţină resursele necesare în limite de timp rezonabile;
c) excluderea mutuală a proceselor care solicită aceeaşi resursă
nepartajabilă şi şi evitarea situaţiilor de blocare (aşteptare fără
sfârşit a unei resurse de către mai multe procese).
Procesul sistem care se ocupă de toate aceste probleme se numeşte
planificator scheduler. Planificatorul determină ordinea de execuţie a job-
urilor lansate de utilizatori, el alege momentul pentru lansarea unei execuţii
şi refuză accesul unui utilizator interactiv dacă numărul de utilizatori
conectaţi poate conduce la o degradare inacceptabilă a timpului de răspuns.
Scopul planificatorului este de a asigura o exploatare echilibrată şi în
consecinţă un serviciu satisfăcător pentru toţi utilizatorii.

Interfaţa utilizator-sistem
Interfaţa între utilizator şi sistemul de operare se efectuează prin
intermediul unui limbaj, numit limbaj de comandă. Natura acestui limbaj
depinde de sistemul considerat.
Sistemele batch sunt dotate cu un limbaj relativ suplu şi puternic,
permiţând utilizatorului să specifice în avans succesiunea prelucrărilor de
realizat, ţinând cont de toate alternativele posibile.
Sistemele interactive oferă interfeţe mai simple prin care utilizatorul
poate urmări derularea job-ului său şi decide succesiunea operaţiilor pe
măsură ce se prezintă situaţiile posibile.
În majoritatea sistemelor actuale, modurile de lucru batch şi multiacces
coexistă, iar limbajul de comandă este adaptat în mod corespunzător.
Tendinţa actuală este de a simplifica sarcina utilizatorului, propunându-i
un repertoar de comenzi uşor de utilizat. Aceste comenzi se exprimă sub
forma cuvintelor cheie (Login, Logout, Edit, Fortran, Run, File, Copy,
Help etc.), urmate de anumiţi parametri. Este de asemenea normală
procedura de lucru prin care se realizează prescurtarea comenzilor (de
exemplu, fl în loc de file list) sau regruparea acestora în fişiere executabile,
un fel de macro-comenzi, de exemplu, se poate înlocui secvenţa Compile,
Link, Load, Run prin procedura Execute.
Directivele pe care utilizatorul le furnizează sistemului cu ajutorul
limbajului de comandă sunt interpretate de către interpretorul de comenzi
command interpreter. Acesta citeşte comenzile provenind de la terminal şi
după interpretarea acestora realizează serviciile solicitate. Datorită

143
dialogului, sistemul trebuie să semnaleze faptul că el „ascultă“ şi este gata să
primească instrucţiunile utilizatorului, răspunzând comenzilor şi
comunicând disponibilitatea sa prin afişarea pe ecran a unui caracter special
prompt, invitând utilizatorul de a formula noi cereri.
Comenzile trimise către sistem sunt o formă de cereri la supervizor
sistem calls, cu deosebirea că, în loc să provină dintr-un program sau
dintr-o procedură de bibliotecă, aceste comenzi sunt comunicate direct
sistemului de către utilizator.
Majoritatea limbajelor de comandă reflectă structura internă a sistemului
de operare, neputând fi schimbate decât cu mare greutate. Totuşi, în cazul
sistemului Unix, interpretorul de comenzi, numit shell, poate fi modificat sau
chiar înlocuit de către utilizator, care poate să comunice astfel cu sistemul
într-un limbaj convenabil ales.
Shell-ul interpretează comenzile provenind de la un terminal sau de la un
fişier shell script şi posedă structuri de control puternice, permiţând
execuţia condiţionată sau repetată a unei succesiuni de comenzi.
Cu abordarea shell, este uşor de a combina proceduri existente şi diverse
elemente de programare; adesea se utilizează shell-ul pentru a se evita
scrierea de noi programe.

Interfaţa utilizator grafică


Până la debutul anilor ‘80, toate interfeţele utilizator erau bazate pe
limbaje de comandă ca shell-ul sistemului Unix. Pentru fiecare acţiune de
efectuat, utilizatorul trebuia să cunoască şi să tasteze numele comenzii.
În laboratoarele Xerox Park, a fost elaborat un nou tip de interfaţă, şi
anume interfaţa grafică GUI: Graphical User Interface, bazată pe utilizarea
unui ecran grafic în locul unui ecran alfanumeric.
Au apărut noi concepte, principalele fiind acelea de ferestre, pictograme,
meniuri care defilează, mouse etc.
Acest tip de interfaţă a devenit la modă prin intermediul familiei
Macintosh elaborată de firma Apple.
La ora actuală, majoritatea sistemelor de calcul utilizează interfeţe
utilizator grafice.
Introducerea grafismului în interfeţele utilizator a revoluţionat lumea
informaticii, în principal prin aceea că permite publicului larg să utilizeze
calculatoarele prin imagine, fără a cunoaşte un jargon specific.
După revoluţia imaginii se estimează că va veni revoluţia sunetului,
recunoaşterea vocală din cadrul interfeţelor om-maşină.

144
8 SISTEMELE DE OPERARE ACTUALE

Sistemele de operare se clasifică în două categorii:


a) sisteme proprietare, care sunt sisteme specifice unei maşini sau
unei game de maşini ale unui anumit constructor, ca de exemplu
VMS, elaborat de firma DEC pentru gama VAX, MS-DOS, pentru
microcalculatoare bazate pe microprocesoare Intel, VM, pentru
calculatoare IBM, MACOS pentru Macintosh al firmei Apple etc.
b) sisteme deschise, care sunt sisteme portabile pe diverse maşini.
Sistemul Unix este exemplul tipic al unui sistem deschis, el a fost
implementat pe maşini dintre cele mai diverse, de la
microcalculatoare şi până la supercalculatoare.
Sistemele proprietare au tendinţa să dispară în beneficiul sistemelor
deschise standard.
O nouă generaţie de sisteme de operare deschise se dezvoltă la ora
actuală, (ca de exemplu, sistemul Windows NT al firmei MicroSoft) sisteme
deschise care funcţionează în regim de multiprogramare, multiutilizator, cu o
interfaţă grafică, şi care integrează multiple posibilităţi de lucru în reţea.

8.1 Sistemul DOS

DOS Disk Operating System este un sistem de operare care cuprinde


programe de interfaţă între utilizator şi sistemul de calcul stocate pe disc.
Structura sistemului de operare DOS este următoarea:
a) Componenta ROM-BIOS este livrată de către firma producătoare a
sistemului de calcul şi are rolul de a egaliza toate diferenţele
constructive ale sistemelor de calcul faţă de convenţiile DOS, deci
calculatoarele sunt compatibile. ROM-BIOS oferă rutine de

145
întrerupere prin care se realizează legătura cu toate unităţile
periferice conectate la sistem;
b) Componenta DISK-BIOS, este independentă de hardware-ul
sistemului de calcul şi ea extinde funcţiile ROM-BIOS. Această
componentă este materializată printr-un fişier disc care, în funcţie de
versiunea sistemului de operare poate avea unul dintre numele:
IBMBIO.COM, BIO.COM, IO.SYS, şi este rezidentă pe discheta
sau discul Wincester de pe care se încarcă sistemul. Funcţiile BIOS
care vizează a) şi b) au în vedere următoarele sarcini:
 încărcare sistem de operare;
 determinarea şi testarea echipamentelor periferice;
 testarea memoriei RAM;
 funcţii de bază asupra ecranului video;
 funcţii elementare de citire a tastaturii;
 funcţii elementare de lucru cu dischetele sau cu hard-discul;
 funcţii de lucru cu caseta magnetică;
 funcţii de lucru cu liniile de comunicaţie asincronă
(imprimantă, scanner, plotter etc.);
Pentru lucrul cu discul, BIOS operează cu cilindri, piste şi sectoare.
c) Componenta BDOS extinde funcţiile BIOS la un nivel mai înalt, în
special către lucrul cu discurile. Această componentă este
materializată printr-un fişier disc care, în funcţie de versiunea
sistemului de operare poate avea unul dintre numele:
IBMDOS.COM, DOS.COM, MSDOS.SYS, şi este rezidentă pe
discheta sau discul Wincester de pe care se încarcă sistemul. Cele
mai importante sarcini BDOS sunt următoarele:
 gestiunea memoriei: alocarea şi eliberarea spaţiului de memorie
necesar programelor;
 gestiunea proceselor (programelor);
 execuţia operaţiilor de intrare/ieşire cu periferice de tip caracter;
 tratarea fişierelor disc: creare, deschidere, închidere, accesare,
ştergere;
 partajarea fişierelor între mai multe procese active la un
moment dat;
 gestiunea structurii arborescente a fişierelor şi manipularea
directoarelor ;
 gestiunea reţelelor de calculatoare;
 modificări ale sistemului de întrerupere;
 gestiunea ceasului intern şi a calendarului.

146
d) Componenta COMMAND are ca sarcină principală preluarea
comenzilor formulate de utilizator de la tastatură şi lansarea lor în
execuţie. Această componentă este materializată prin fişierul disc
COMMAND.COM. Comenzile DOS sunt de două tipuri:
 comenzi interne, înglobate în COMMAND şi încărcate permanent
în memorie. De regulă, acestea sunt comenzi mai simple şi de primă
utilitate: rezumate de disc, copieri de fişiere etc.
 comenzi externe, rezidente pe disc sub forma unor programe
executabile sau sub forma unor fişiere de comenzi (fişiere text
în care sunt apelate alte comenzi DOS). De regulă, comenzile
externe sunt mai complexe decât cele interne.
În timpul introducerii comenzilor, DOS recunoaşte o serie de funcţii de
control, din care amintim câteva:
 <CTRL/C> sau <CTRL/Break>: abandonează linia de comandă;
 <F3>: copiază pe ecran ultima linie introdusă;
 <CTRL/P>: trimite în ecou ieşirea pe ecran şi imprimantă;
 <CTRL/N>: anulează efectul lui <CTRL/P>;
 <CTRL/S>: opreşte temporar defilarea ecranului, repornirea se
realizează prin apăsarea oricărei taste cu excepţia <CTRL/C>;
 <F6> sau <CTRL/Z>: inserează marcator de sfârşit fişier;
 <F1>: copiază un caracter din şablon şi îl afişează;
 <F2>: copiază toate caracterele care preced un caracter specificat.
Generarea sistemului de operare DOS pe o dischetă sau pe un hard-disc se
realizează prin intermediul unor comenzi standard, ştergând toate informaţiile
vechi de pe discul respectiv. Etapele generării unui disc DOS sunt următoarele:
a) Partajarea hard-discului: împărţirea în una până la patru zone
contigue numite partiţii. În acest fel, în loc de un singur disc mare,
DOS „vede” mai multe discuri mici. Operaţia de partajare se
realizează cu ajutorul programului FDISK, care printr-un dialog cu
utilizatorul realizează partiţionarea la dimensiunile dorite;
b) Formatarea discului. Comanda DOS FORMAT realizează
formatarea discului (împărţire în cilindri, piste, sectoare) şi
verificarea sectoarelor sale. Tot prin această comandă se crează
discul sistem DOS (opţiunea /S), iar ca efect, pe discul respectiv se
realizează următoarele:
 în sectorul 0 se pune programul bootstrap de încărcare a
sistemului de operare;
 se depun pe disc fişierele IBMBIO.COM, IBMDOS.COM şi
COMMAND.COM;
 în restul sectoarelor se pune valoarea 0.

147
Dacă s-a procedat la partajarea hard-discului este necesară formatarea
tuturor unităţilor de disc logic care au ca suport fizic discul partajat.
Este suficientă formatarea cu opţiunea „/S” numai a uneia dintre
partiţii (cea care este declarată activă prin FDISK);
c) Crearea fişierului de configurare. La fiecare lansare a sistemului
se execută o operaţie de configurare prin care se fixează valorile
unor parametri sistem, cum ar fi:
 numărul fişierelor deschise simultan;
 numărul zonelor tampon pentru operaţiile de intrare/ieşire;
 numărul şi dimensiunea stivelor;
 condiţia de sesizare a tastării <CTRL/Break>;
 convenţiile de ţară, timp, monedă;
 precizarea unor noi drivere de intrare/ieşire;
Aceşti parametri sunt precizaţi prin intermediul unui fişier text numit
CONFIG.SYS. Dacă fişierul nu este prezent pe disc, atunci DOS
atribuie acestor parametri nişte valori implicite, care depind de tipul
sistemului de calcul. De obicei, conţinutul acestui fişier este stabilit
la generare în funcţie de configuraţia hardware şi de aplicaţiile care
vor fi rulate pe sistemul respectiv. Fişierul se crează simplu, cu
ajutorul unui editor de texte, eventual el poate fi pregătit dinainte,
urmând a fi copiat pe noul disc;
d) Crearea fişierului de comenzi iniţiale. În momentul lansării
sistemului, după fixarea parametrilor de configurare şi după
încărcarea interpretorului de comenzi, DOS caută pe disc un fişier
cu numele AUTOEXEC.BAT. Acesta este un fişier text în care
utilzatorul trece toate comenzile DOS care se doresc a fi executate la
lansarea sistemului. De obicei, aceste comenzi se referă la:
 fixarea de către utilizator a datei şi orei exacte de pornire;
 fixarea modului de afişare a prompterului de invitare la comenzi;
 precizarea directoarelor de pe disc unde DOS caută comenzile
externe.
La fel ca şi CONFIG.SYS, fişierul AUTOEXEC.BAT poate fi
pregătit (eventual în avans) folosind un editor de texte.
e) Copierea fişierelor dorite pe discul sistem. Se realizează cu
comanda XCOPY.
Sistemul DOS dispune de comanda internă SELECT destinată realizării
automate a ultimelor 3 etape.

Organizarea şi specificarea fişierelor DOS

148
Sistemul de operare DOS, începând cu versiunea 2.0 adoptă un sistem de
fişiere organizat arborescent. În forma cea mai simplă, un fişier obişnuit se
specifică astfel: nume. tip, unde nume are maximum 8 caractere, iar tip are
maximum 3 caractere.
Fişierele speciale DOS au nume predefinite, care nu pot fi utilizate ca
nume pentru fişierele obişnuite. Numele rezervate sunt:
 CON desemnează tastatura, dacă este folosit ca fişier de intrare,
respectiv ecranul terminalului, dacă este folosit ca fişier de ieşire;
 PRN (având ca sinonim LPT1), LPT2, LPT3 desemnează una dintre
imprimantele paralele;
 AUX (având ca sinonim COM1), COM2, COM3 şi COM4
desemnează unul dintre adaptoarele de comunicaţii asincrone);
 NUL este numele unui fişier (echipament) fictiv. Folosit ca fişier de
intrare generează imediat pentru sistemul de gestiune a fişierelor
marcatorul de sfârşit de fişier, iar folosit ca fişier de ieşire,
informaţiile „scrise” în el nu sunt de fapt depuse nicăieri.
În forma cea mai generală, un fişier pe suport disc se specifică prin cele
patru zone, adică: periferic cale nume .tip, unde:
 perferic se va specifica printr-o literă urmată obligatoriu de „:”.
DOS poate avea maximum 26 de periferice de tip disc notate cu
literele alfabetului, începând cu A. În mod obligatoriu literele A: şi
B: desemnează dischete. Dacă sistemul de calcul dispune de hard
disc el (primul dintre ele) va fi notat cu C:, apoi pot urma şi alte
periferice de tip disc. Dacă lipseşte specificarea pentru periferic,
sistemul presupune că este vorba despre perifericul implicit;
 cale indică, după caz, succesiunea directoarelor de la rădăcină până
la fişier (primul simbol din cale este „\“) sau de la directorul curent
până la fişier (când cale nu începe cu „\“). Separarea directoarelor
DOS se face cu simbolul „\“. Dacă specificarea de cale lipseşte,
atunci sistemul consideră că fişierul face parte din directorul
curent. Sistemul DOS reţine câte un director curent pentru fiecare
periferic disc din sistem şi de aceea, atunci când se trece de la un
periferic la altul fără să i se indice acestuia calea, sistemul consideră
că este vorba despre directorul curent al perifericului respectiv.
 tip poate lipsi, dar în general se foloseşte pentru a indica conţinutul
fişierului. Câteva tipuri sunt uzuale: BAS, FOR, PAS, C, ASM, OBJ,
EXE, COM, BAT, LST, DAT, DOC, TXT, MAP, LIB, TMP, BAK.
Unele comenzi DOS acceptă specificarea generică a unei familii de fişiere.
Aceasta presupune folosirea, numai în zona de nume sau tip (eventual în

149
ambele) a simbolurilor speciale: „*”, care poate substitui un grup de caractere,
sau „?”, care poate substitui un caracter pe poziţia pe care se găseşte.
Iată câteva exemple de nume de fişiere:
PROG.PAS, PROG;
B: ALFA. UNU, B: ALBA. DOI, B: ALGA. COM;
C: \ programe\ pascal\ *. PAS
Primele două fişiere se află pe perifericul implicit şi în directorul curent.
Următoarele trei fişiere sunt pe discul B: şi în directorul implicit.
Specificarea generică PROG.* include primele două fişiere. Specificarea B:
AL?A.* conţine cele trei fişiere de pe discul B:.
Specificarea C: \ programe\ pascal\ *. PAS conţine toate textele sursă Pascal
aflate în directorul numit pascal, care este subdirector al directorului programe,
care este subdirector al rădăcinii discului C:. Dacă directorul curent este
\programe, atunci specificarea poate fi făcută şi sub forma C: \ pascal\ *. PAS.

Structura internă a unui disc DOS


Un sector al unui disc este fie liber, fie ocupat de un fişier anume, fie
conţine informaţii destinate special sistemului de operare.
În sistemul DOS, unitatea de alocare a spaţiului pe disc este cluster-ul.
Un cluster este o succesiune de 1 până la 8 sectoare vecine, alocate împreună
aceluiaşi fişier. Dimensiunea unui cluster este o constantă care depinde de
tipul discului şi de tipul sistemului de calcul. Valoarea acestei constante este
în cazurile următoare:
 1 sector / cluster, pentru o dischetă simplă faţă;
 2 sectoare / cluster, pentru o dischetă dublă faţă;
 4 sectoare / cluster, pentru un hard disc al unui IBM PC / AT;
 8 sectoare / cluster, pentru un hard disc al unui IBM PC / XT;
Pentru a vedea modul în care un anumit fişier utilizează clusterii unui
disc fizic, este necesar să parcurgem mai multe etape, care în abordarea top-
down (de sus în jos) ar fi:
a) partiţionarea unui hard disc în discuri logice;
b) structura şi alocarea spaţiului la un disc logic;
c) structura şi reprezentarea unui director;
d) manipularea fişierelor şi articolelor.

Structura şi alocarea spaţiului la un disc logic


Un disc logic este fie o dischetă fizică, fie o partiţie de hard disc, fie un
ramdrive (disc simulat în memoria RAM). Un disc logic este împărţit în
patru zone şi anume:

150
a) Zona de boot conţine informaţii care sunt utilizatecând se încarcă
sistemul de operare. Aceste informaţii sunt dependente de sistem,
dar în mod tipic conţin un program de încărcare;
b) FAT - Tabela de alocare a fişierelor conţine informaţii cu ajutorul
cărora se gestionează spaţiul pe disc. În FAT este înregistrată starea
zonelor de pe disc divizate în entităţi numite clustere. Pentru a
cunoaşte lungimea unui cluster indiferent de disc se va specifica
comanda CHKDSK. Alocarea clusterelor se realizează prin
intermediul FAT care conţine o listă de numere care reprezintă
fiecare cluster alocat pe disc:
 dacă intrarea în FAT este 0, atunci clusterul este liber;
 dacă intrarea în FAT este nenulă, atunci este un cluster în
folosinţă, iar numărul găsit este utilizat pentru a lega diferite
clustere care alcătuiesc împreună fişierul;

FAT
4 5 7 8 EMPTY
cluster
2 3 4 5 6 7 8
c) ROOT directory - directorul rădăcină, simbolizat prin „ \ “ este
un director în care se memorează, pentru fiecare fişier următoarele
infirmaţii:
 numele şi extensia sa;
 data creării sau a modificării (vizibile cu comanda DIR);
 numărul de început al clusterului (clusterul care conţine prima
înregistrare a fişierului);
 atributul fişierului;
d) File - Zona alocată fişierelor conţine în prima parte fişierele
sistemului de operare IBMBIO. COM şi IBMDOS. COM şi în
continuare, fişierele divizate în clustere a căror ordine de legături
este păstrată în FAT. Subdirectorii sunt localizaţi în FAT ca orice alt
fişier, iar atunci când se utilizează conţinutul unui subdirector, acesta
acţionează ca şi directorul rădăcină.

Principalele comenzi DOS


Interpretorul de comenzi COMMAND. COM se încarcă în memorie la
pornirea sistemului de operare. El ţine evidenţa discurilor implicite şi a

151
directoarelor curente de pe fiecare disc şi în plus, efectuează un număr de
comenzi DOS prestabilite.
Comenzile DOS se împart în două categorii:
a) comenzi rezidente (interne), sunt comenzile înglobate în
COMMAND. COM;
b) comenzi tranzitorii (externe), sunt cele care solicită existenţa pe
disc a unui fişier de tip .COM sau .EXE având ca nume numele
comenzii.
O comandă rezidentă se lansează astfel: ... > comanda argumente, iar o
comandă rezidentă: ... > comanda d: cale argumente.
Ca efect, COMMAND.COM caută şi reperează pe disc un fişier având
unul din numele: comanda.COM, comanda.EXE, comanda.BAT
Dacă se specifică „d:”, atunci căutarea se face pe discul specificat, în caz
contrar se caută pe discul implicit.
Dacă se specifică „cale”, atunci fişierul se caută în directorul indicat de cale.
În situaţia în care lipseşte atât specificarea de disc cât şi specificarea de
cale, căutarea se face în ordine:
 în directorul curent;
 în directoarele specificate prin comanda PATH.
În cazul în care, în acelaşi director este reperat mai mult de un fişier din
cele trei, de exemplu, unul de tip COM şi altul de tip BAT, prioritatea la
lansare o are COM, apoi EXE şi la urmă BAT.
O sinteză a formatului comenzilor DOS cu principalele opţiuni este
prezentată în figura următoare. Comenzile interne sunt evidenţiate prin litera
„I” plasată în dreapta comenzii.
CD d:cale sau CHDIR d:cale I
MD d:cale sau MKDIR d:cale I
RD d:cale sau RMDIR d:cale I
JOIN d1 d2 \director /D
FDISK d:
FORMAT d: /S/V
UNFORMAT d:
LABEL d:etichetă_volum
DISKCOMP d1: d2:
DISKCOPY d1: d2:
CHKDSK d:calefişier. tip/F/V
RECOVER d:
DIR d:calefişier. tip/P/W I
COPY /A/Bd:calefişier. tip
+d:calefişier.tip...d:calefişier.tip I

152
XCOPY d:calefişier. tip d:calefişier. tip
/A/D: ll-zz-aa/E/M/P/S/V/W
REN sau RENAME d:calefişier.tip d:calefişier.tip I
DEL sau ERASE d:calefişier.tip I
UNDELETE d:calefişier.tip/LIST/ALL
COMP d:calefişier.tip d:calefişier.tip
TYPE d:calefişier.tip I
PRINT d:calefişier.tip ... /C/P/T
SORT /R/+n
FIND /V/C/N „şir” sau d:calefişier.tip ...
MORE
EXE2BIN d:calefişier. COM d:calefişier. EXE
PATH d:cale;d:cale ... I
APPEND d:cale;d:cale ...
FASTOPEN d: = n
DATE ll-zz-aa I
TIME hh-mm:ss I
BREAK ONOFF I
PROMPT text I
SET nume = valoare I
CLS
MEM /P/C/D
VER I
VOL d: I
HELP comanda

Principalele comenzi DOS pot fi grupate astfel:


a) Comenzi de manipulare a directoarelor:
 CD (CHDIR): schimbă directorul curent în cel specificat;
 MD (MKDIR): crează un director nou, numai dacă nu există
deja un director cu numele specificat;
 RD (RMDIR): şterge un director vid (nu conţine nici-un fişier
sau subdirector specificat);
 JOIN: realizează conectarea unei structuri de fişiere aflată pe un
disc „d1” la structura de fişiere a discului „d2”. În urma
comenzii, cele două sisteme de directoare sunt privite ca şi unul
singur, directorul rădăcină al discului „d1” fiind conectat ca
subdirector cu numele „director” al rădăcinii lui „d2”. Opţiunea

153
„/D” realizează operaţia inversă, adică deconectarea, iar atunci
se vor specifica numai „d1” şi „/D”;

b) Comenzi de manipulare a unui disc:


 FDISK: realizează partajarea unui hard disc în partiţii;
 FORMAT: iniţializează discul specificat prin „d:” la un format
standard acceptat de către DOS. După ce se scrie pe tot discul,
se crează directorul rădăcină şi se iniţializează directorul
rădăcină precum şi tabela FAT. Opţiunea „/S” cere ca discul
respectiv să fie făcut disc sistem, opţiunea „/V” specifică o
etichetă de volum pentru identificare;
 UNFORMAT: permite refacerea unui disc formatat, indicat prin
„d:”. Comanda este valabilă la DOS 5.0, iar refacerea se
realizează prin formatarea doar a părţii de început, până la
directorul rădăcină inclusiv. Înainte de scriere, această porţiune se
salvează într-o zonă rezervată a discului. Utilizatorul trebuie să
lanseze comanda UNFORMAT înainte de a scrie ceva pe discul
formatat, iar dacă nu se respectă această condiţie, sau se lansează
FORMAT cu „/U”, atunci refacerea nu mai este posibilă;
 LABEL: permite crearea sau ştergerea unei etichete de volum.
Această etichetă poate fi dată şi prin comanda FORMAT,
printr-un dialog între sistem şi utilizator;
 DISKCOMP: permite compararea dischetelor indicate prin „d1” şi
„d2”. Comparaţia se face pistă cu pistă, semnalându-se diferenţele.
De regulă, această comandă se dă pentru a se verifica dacă s-a făcut
corect o operaţie de copiere cu comanda DISKCOPY;
 DISKCOPY: copiază la nivel fizic, discheta „d1” pe discheta
„d2” (dacă e nevoie, discheta „d2” este formatată automat);
 CHKDSK: analizează structura informaţiei de pe un disc DOS şi
afişează un raport asupra stării discului. Opţiunea „/F” cere corectarea
(pe cât posibil a) structurii încât să devină una validă, iar opţiunea
„/V” afişează o serie de detalii în timpul execuţiei comenzii. Dacă se
specifică un fişier (sau o familie), atunci se indică numărul de zone
necontigue ocupate de fişierul (fişierele) în cauză.
 RECOVER: recuperează fişierele de pe disc care conţin
sectoare defecte, şi de asemenea, se marchează sectoarele
defecte. Fişierele recuperate primesc nume noi, sub forma:
FILEnnnn. REC, unde „nnnn” este un număr de ordine. Toate
fişierele recuperate vor fi plasate în directorul rădăcină.

154
c) Comenzi referitoare la fişiere:
 DIR: listează toate intrările din fişierul director sau numai cele
specificate. Parametrul „/P” generează execuţia unei pauze ori
de câte ori ecranul este plin de informaţii, iar parametrul „/W”
produce o afişare condensată a directorului, listând doar
numele fişierelor, câte cinci nume pe linie;
 COPY: copiază unul sau mai multe fişiere pe un alt disc şi
opţional, atribuie un nume diferit pentru copie. De asemenea,
COPY poate crea o copie pe acelaşi disc. În timpul procesului
de copiere se poate realiza şi o concatenare de fişiere, dacă se
specifică operatorul „+”. Parametrii „/A” şi „/B” indică
volumul de date care se va copia şi anume:
- în intrare: „/A” exclude copierea marcatorului de sfârşit de
fişier, iar „/B” impune copierea întregului fişier;
- în ieşire: „/A” adaugă marcatorul de sfârşit de fişier, iar „/B”
nu adaugă marcatorul de sfârşit de fişier;
 XCOPY: permite copierea selectivă de fişiere sau grupuri de
fişiere care pot să includă şi subdirectoare. Ca opţiuni, pot fi:
- „/A”: copierea fişierelor marcate pentru arhivare;
- „/M”: identic cu „/A”, dar schimbă marcajul de arhivare;
- „/D”: copierea fişierelor modificate după data specificată;
- „/E”: crează la destinaţie subdirectoarele din sursă;
- „/P”: copierea cu confirmare pentru fiecare fişier;
- „/S”: copierea din sursă a directoarelor şi subdirectoarelor
- „/V”:verificare scriere la destinaţie (recitire şi comparare)
 REN (RENAME): schimbă numele fişierului specificat;
 DEL (ERASE): şterge fişierul cu numele specificat, din
directorul şi unitatea specificate sau implicite;
 UNDELETE: permite refacerea fişierelor şterse (valabilă la DOS
5.0). În mod obişnuit se reface un singur fişier, dar opţiunea
„/ALL” permite refacerea tuturor fişierelor posibile, caz în care
prima literă a numelor acestor fişiere este stabilită automat.
Opţiunea „/LIST” permite afişarea fişierelor care pot fi refăcute;
 COMP: compară două fişiere de aceeaşi lungime, prin citirea şi
compararea conţinutului lor. Compararea se termină fie la sfârşit,
fie la depistarea a maximum 10 octeţi diferiţi ( primele 10
diferenţe sunt afişate);
 TYPE: afişează conţinutul fişierului specificat pe dispozitivul
standard de ieşire;

155
 PRINT: tipăreşte o coadă (listă) de fişiere de date la imprimantă
în timp ce pe sistem se pot executa alte lucrări;

d) Filtre DOS:
 SORT: citeşte date de la echipamentul standard de intrare,
sortează datele, apoi scrie datele sortate la echipamentul
standard de ieşire. Sortarea se efectuează crescător după
codurile ASCII ale caracterelor, sau descrescător („/R”);
 FIND: trimite la echipamentul standard de ieşire toate liniile din
fişierul specificat în comandă şi care conţin un şir de caractere
specificat. Parametrul „/V” determină afişarea tuturor liniilor
care nu conţin şirul specificat, iar parametrul „/C” permite
afişarea unui contor cu numărul de apariţii a şirului specificat;
 MORE: este un filtru care citeşte date de la intrarea standard şi
le transpune pe ecran, iar când acesta este plin, se aşteaptă
apăsarea unei taste pentru a se trece la ecranul următor;
 EXE2BIN: este un filtru special care transformă un program
executabil de tip EXE în unul de tip COM;

e) Comenzi de configurare dinamică DOS:


 PATH: fixează căile de căutare a fişierelor executabile;
 APPEND: fixează căile de căutare a fişierelor neexecutabile;
 FASTOPEN: optimizează accesul la fişierele şi directoarele
folosite mai des. În acest scop se gestionează o zonă tampon cu
adresele disc recent utilizate, potrivit principiului memoriei
cache. Parametrul „n” indică numărul de adrese gestionate,
cuprins între 10 şi 999, cu valoarea implicită 34;
 DATE, TIME, BREAK, PROMPT: se referă la schimbarea
datei, a orei exacte, a sesizării sau nu a lui <CTRL/Break>, sau
a formei prompterului de invitare la comenzi;
 CLS: provoacă ştergerea completă a ecranului terminalului
 SET: fixează valori ale unor parametri aflaţi într-o zonă de
memorie controlată de COMMAND. COM.

f) Comenzi de informare:
 MEM: afişează conţinutul memoriei la un moment dat;
 VER: afişează versiunea sistemului de operare DOS;
 VOL: afişează eticheta de volum specificat sau a celui curent;
 HELP: oferă detalii despre comenzile DOS în general, sau
despre o anumită comandă DOS specificată.

156
Fişiere de comenzi (BAT) sub DOS
Un fişier de comenzi (al cărui tip este . BAT), este un fişier text care
conţine una sau mai multe comenzi şi/sau directive care se execută succesiv,
fără intervenţia directă a utilizatorului. Un prim exemplu de fişier de
comenzi DOS este fişierul AUTOEXEC. BAT. Dacă acest fişier este prezent
în directorul rădăcină pe discul de pe care se face încărcarea, DOS execută
automat comenzile din el la fiecare încărcare a sistemului.
Un fişier de comenzi DOS conţine mai multe tipuri de construcţii:
- comenzi DOS propriu-zise;
- etichete;
- caracterele speciale , <, > şi %;
- parametrii formali care vor fi înlocuiţi la lansare cei actuali;
- variabile globale rezidente în interpretorul de comenzi;
- variabile locale utilizate în instrucţiuni repetitive;
- directive adresate interpretorului fişierelor de comenzi.
Exemplu: TIPAR. DAT: DIR *. PAS
COPY *. PAS a:
DEL *. PAS
O etichetă se scrie sub forma: : nume, unde caracterul „:” este urmat de
maximum 8 litere sau cifre. O etichetă apare pe o singură linie, la început de rînd.
Caracterele speciale , < şi > sunt interpretate în comenzi prin legare în
pipe a două comenzi, respectiv redirectarea intrării şi/sau ieşirii standard a
unei comenzi.
Caracterul % marchează parametrii formali, variabilele globale şi
variabilele locale.
Într-un fişier de comenzi pot fi specificaţi până la 10 parametri formali,
notaţi %0, %1, ..., &9. Corespunzător acestora, în linia de comandă care
lansează în execuţie fişierul de comenzi argumentele sunt puse în
corespondenţă cu aceşti parametri.
De exemplu, în figura următoare este dat un fişier de comenzi care
compilează două programe Fortran şi le leagă într-un fişier executabil.
Primele două argumente dau numele celor două texte sursă, iar al treilea
numele programului executabil.
Dacă se lansează fişierul prin comanda: ... FORTR XAA YBB REZ
atunci parametrii formali vor avea valorile:
%0 FORTR;
%1 XAA;
%2 YBB;
%3 REZ.

157
FORTR. BAT: WS %1. FTN
FOR %1, %1, %1
PH2 %1
WS %2.FTN
FOR %2, %2, %2
PH2 %2
LINK %1+ %2, %3, FORTRAN
DEL %1. BAK
DEL %1. OBJ
DEL %2. BAK
DEL %2. OBJ

Directivele interpretorului fişierelor de comenzi


- FOR %% variabila IN (mulţime) DO comanda;
- CALL fişier_comenzi;
- IF NOT ERRORLEVEL n comanda, sau
- IF NOT şir1 == şir2 comanda sau
- IF NOT EXIST fişier
- GOTO etichetă
- SHIFT
- ECHO ONOFFmesaj
- PAUSE mesaj
Directiva FOR permite prelucrarea iterativă a unei comenzi dintr-un
fişier de comenzi. %%variabilă este o variabilă locală de ciclare care va fi
înlocuită secvenţial cu fiecare membru din mulţime, apoi comanda este
evaluată şi executată. Dacă un membru al mulţimii este o expresie construită
generic (cu * şi/sau ?), atunci %%variabilă va fi înlocuită pe rând cu toate
numele de fişiere care se potrivesc cu această expresie.
De exemplu, comanda:
FOR %%f IN (*.PAS *.DOC) DO TYPE %%f
va tipări pe ecranul terminalului mai întâi toate fişierele de tip PAS, apoi
pe cele de tip DOC.
Directiva CALL permite apelul (lansarea în execuţie) a unui fişier de
comenzi din altul. La terminarea fişierului apelat, controlul revine fişierului
apelant. Este posibil ca ultima linie a unui fişier de comenzi să ceară
lansarea altui fişier de comenzi (fără CALL), şi în acest caz se realizează o
înlănţuire fără revenire a celor două fişiere.
Directiva GOTO transferă controlul în fişierul de comenzi, în linia de
comandă situată după eticheta specificată.

158
Directiva IF permite execuţia condiţionată a unei comenzi DOS din
fişierul de comenzi, sau a unei alte directive.
Fiecare comandă DOS transmite, în momentul terminării, un cod cu o
valoare între 0 şi 255. De obicei, un cod cu o valoare nenulă indică o situaţie
neobişnuită, în anumite situaţii de programare specificând ramura pe care s-a
terminat programul. Condiţia „ERRORLEVEL număr” este adevărată
dacă codul de retur al ultimei comenzi este mai mare sau egal cu numărul
scris după cuvântul ERRORLEVEL.
Condiţia „şir1 == şir2” este adevărată dacă valorile celor două şiruri de
caractere coincid, iar cel puţin unul din şiruri trebuie să conţină un parametru
formal sau o variabilă globală.
Condiţia „EXIST fişier” este adevărată dacă fişierul specificat, simplu
sau generic există.
Acţiunea directivei IF fără NOT înseamnă execuţia comenzii dacă
condiţia este adevărată, iar dacă NOT este prezent, atunci comanda se
execută când condiţia este falsă.
Comanda ASK face parte dintr-o familie de programe utilitare oferite de
firma NORTON. Prin intermediul acestei comenzi, utilizatorul poate
interacţiona cu fişierul de comenzi.
ASK mesaj, litere are ca efect afişarea pe ecran a „mesaj”, care nu
conţine „,”, după care aşteaptă ca utilizatorul să apese una din literele dintre
paranteze . Dacă utilizatorul a tastat a i-a literă din listă, atunci ASK se
termină cu ERRORLEVEL = i. Evident, o succesiune de directive IF poate
realiza o ramificare multiplă a execuţiei.

Exemplu: ASK. BAT: ASK Doriţi testare AV?, DdNn


IF ERRORLEVEL 3 GOTO :FĂRĂ
SCAN c: d:
PAUSE
: FĂRĂ

Directiva SHIFT permite folosirea a mai mult de 10 parametri formali.


Efectul ei este acela de a „decala” parametrii formali, făcând să se piardă
parametrul %0, parametrul care înainte era %1 să devină %0, cel ce fusese
%2 să devină %1 etc.
Exemplu: STERGE.BAT:
:IAR
SHIFT
IF ”%0” == ” “ GOTO :STOP

159
DEL %0
GOTO :IAR
:STOP
Lansat cu ...> STERGE a b c d e f g h i j k l va şterge pe rând cele 12
fişiere citate în comandă.
Directiva ECHO permite să se afişeze (ON) sau să nu se afişeze (OFF)
comenzile care se execută, sau dacă directiva conţine un mesaj, se afişează
acest mesaj pe ecran.
Directiva PAUSE suspendă execuţia fişierului de comenzi până la
apăsarea unei taste.
Întreruperea execuţiei unui fişier de comenzi se face cu <CTRL/C>.

Utilitare DOS. NC (Norton Commander)


Programul utilitar NC este compus dintr-un pachet de programe de
dimensiune maximă 720K pe disc, solicită resurse destul de mici, de
exemplu, partea rezidentă în memorie este de 12K, fiind utilizat mult
datorită eleganţei cu care se operează şi a popularităţii sale.
Lansarea în execuţie a utilitarului se realizează prin ... > NC.
Întreaga interfaţă cu utilizatorul este realizată în modul de lucru text,
asigurându-se astfel o viteză mare de răspuns.
În mod obişnuit, NC gestionează 2 ferestre alăturate, pe care le numeşte
Left şi Right. Este posibil ca una sau chiar ambele ferestre să nu fie active,
iar în spaţiul eliberat de fereastra devenită temporar inactivă utilizatorul vede
ecranul gestionat de programul lui sau de DOS.
Prima linie marchează locurile unde pot să apară cele 5 meniuri
principale pull-down ale lui NC. În partea dreaptă sus, poate fi afişată
(opţional) ora exactă gestionată de sistem.
În fiecare dintre cele două ferestre principale apar informaţii din două
directoare curente gestionate de NC. Calea din rădăcină pentru cele două
directoare este scrisă în partea superioară a fiecărei ferestre.
Informaţiile despre un fişier al unui director sunt scrise într-o singură
linie dintr-o fereastră principală. În fiecare fereastră NC marchează câte un
fişier curent, iar în partea de jos a fiecărei ferestre se trec informaţiile
complete despre fişierul curent: nume, lungime, data şi ora de creare.

Left Files Commands Options Right 6:0p


C:\HELP4 D: \T\CURENT

Fereastra principală Fereastra principală


Left Right

160
Fişier curent Left Fişier curent Right

D: \CURENT>

1Help2Menu 3View 4Edit 5Copy 6Ren7 Mkdir 8Delete 9PullDn 10Quit

Penultimul rând al ecranului afişează prompterul DOS şi acolo apar


comenzile DOS date de utilizator.
Ultimul rând afişează opţional semnificaţiile pentru NC ale tastelor
funcţionale de la F1 la F10.
NC poate fi manipulat atât prin apăsarea de taste cât şi prin „clic”-uri de
mouse. Ca regulă, butonul din stânga înseamnă lansarea în execuţie sau
schimbarea de director.
Tasta <TAB> provoacă trecerea de la o fereastră la alta. Fişierele curente
din cele două ferestre rămân nemodificate. Discul şi directorul din fereastra
în care se află cursorul este discul şi directorul implicit.
Tasta <F9> permite activarea meniurilor pull-down. Prin săgeţile de
deplasare laterală, sau prin testarea primei litere a meniului, se fixează
meniul dorit. Apoi, tastând <ENTER> se deschide o fereastră care oferă
alternativele meniului. Prin săgeţile verticale sau tastând prima literă, după
care se tastează <ENTER>, se selectează alternativa dorită.
Tasta <F10> provoacă terminarea activităţii NC şi revenirea sub sistemul
de operare DOS.
Tasta <F1> este tasta HELP şi ea invocă sistemul de ajutor NC.
Prin meniurile Left şi Right, utilizatorul stabileşte tipul şi ordinea
datelor afişate precum şi modalităţile de schimbare a contextului de lucru.
Afişarea informaţiilor dintr-o fereastră se poate face:
 BRIEF (sumar): numele fişierului şi tipul lui;
 FULL (complet): numele, lungimea, data şi ora de creare;
 INFO (informaţii statistice): lansabile şi cu <CTRL/L>.
 TREE: afişează în fereastră structura arborescentă a discului implicit
din fereastra cealaltă;
 ON/OFF: indică faptul că se doreşte ca fereastra să fie activă sau nu.
Activarea/dezactivarea ferestrei Left se mai poate face cu
<CTRL/F1>, iar a ferestrei Right cu <CTRL/F2>.
Ordinea afişării informaţiilor poate fi:
 alfabetică, după nume;
 alfabetică, după tip;
 după data creării (primul va fi cel mai nou);

161
 după lungimea fişierului (primul va fi cel mai lung);
 după apariţia fizică în director (nesortate).
Se pot realiza schimbări de director sau disc, astfel:
 schimbarea discului se realizează prin meniu cu <ALT/F1>, pentru
fereastra Left şi cu <ALT/F2> pentru Right;
 schimbarea de director se realizează fie cu comanda DOS CD, fie
tastând <ENTER> din aproape în aproape până la directorul dorit;
 filtrările de fişiere cu FILTER furnizează informaţii despre:
- toate fişierele;
- numai cele executabile (COM, EXE, BAT);
- cele cerute cu o specificare generică.

Comenzi NC de manipulare fişiere


NC permite prin săgeţile verticale sau prin <PGUP> şi <PGDN>
schimbarea fişierului implicit. De asemenea, se pot marca mai multe fişiere
pentru a fi manipulate. Marcarea se poate face fie individual, tastând <INS>
pe fişierul dorit pentru marcare, fie prin tasta <+> de culoare gri din dreapta
tastaturii. Demarcarea se face individual tot prin <INS, sau global prin tasta
<->. Fişierele sunt manipulate global dacă ele sunt marcate, altfel este
manipulat fişierul curent.
Taste funcţionale de manipulare a fişierelor:
 <F2> lansare meniu utilizator;
 <F3> sau <SHIFT/F3> vizualizarea unui fişier;
 <F4> sau <SHIFT/F4> editarea unui fişier;
 <F5> sau <SHIFT/F5> copiere fişiere marcate;
 <F6> mutare (redenumire) fişiere;
 <F7> crearea unui director;
 <F8> ştergere fişiere.

Comenzi NC (meniul Commands)


 <ALT/F10>:NCD Tree: afişare structură de directoare;
 <ALT/F7>: căutare de fişiere;
 <ALT/F8>, <CTRL/E> , <CTRL/X>: vizualizare istoric comenzi;
 <ALT/F9>: afişează mai multe linii pe ecran, dacă monitorul este
cel puţin EGA;
 <CTRL/U>: permută ferestrele Left şi Right;
 <CTRL/O>: inactivează ambele ferestre;

162
 Compare directory: comparare de directoare din punct de
vedere al conţinutului şi al datei de creare. Ca efect al comparării se
marchează fişierele dintr-o fereastră care nu sunt în cealată fereastră
sau fişierele dintr-o fereastră care sunt mai recente decât cele
omonime din cealaltă;
 Menu file edit: crează meniuri utilizator;
 Extension file edit: defineşte în mod automat nişte acţiuni cu fişiere
de un anumit tip, de exemplu, şterge automat dacă se tastează
<ENTER> pe un fişier curent de tip BAK, lansează Turbo Pascal pe
un fişier curent de tip PAS etc.

Fixarea unor opţiuni NC


 configurare: permite fixare culoare ecran, fixarea unui termen după
care ecranul se stinge dacă nu se apasă o tastă, afişarea fişierelor cu
atributul HIDDEN (ascuns) etc.;
 fixarea editorului de texte: se poate folosi atât editorul NC cât şi
orice alt editor dorit de utilizator;
 folosirea de către NC a întregului ecran sau numai a unei jumătăţi;
 salvarea setărilor NC: se face cu <SHIFT/F9> şi are ca efect
recrearea fişierului NC.INI al pachetului NC.

8.2 Sistemele Windows

Sistemele Windows sunt sisteme de programe concepute cu o interfaţă


grafică, prietenoasă între utilizator şi calculator, realizate de firma Microsoft.
Aplicaţiilor le sunt asociate simboluri grafice (pictograme), numite icon-uri;
acestea se grupează sau se execută în ferestre. O fereastră este o zonă
dreptunghiulară pe ecran care are anumite caracteristici. Cel mai simplu mod
de a utiliza sistemul Windows este cu ajutorul mouse-ului dar se poate folosi şi
tastatura. Aproape toate programele folosite uzual sub sistemul de operare
DOS, atât medii de programare profesionale, cât şi cele mai variate aplicaţii de
birotică, au ajuns să fie scrise pentru a fi exploatate sub Windows. Însuşi
sistemul Windows s-a dezvoltat prin versiuni succesive, ajungând să
dobândescă caracteristici de sistem de operare (Windows ’95, ’98, 2000,
Windows NT) sau de soft de reţea (Windows NT, 2000).

Evoluţia sistemelor Windows


Sistemele Windows s-au răspândit rapid pe calculatoarele personale (PC)
astfel încât, după anul 1990, a devenit de la sine înţeles ca un asemenea calculator
să dispună de un sistem Windows. Primele versiuni (Windows 3.) rulează sub

163
sistemul de operare DOS dar Windows ’95 a devenit un sistem de operare care
nu mai are nevoie de un sistem DOS preinstalat, fiindcă de fapt încorporează
facilităţile acestuia (versiunea 7 a sistemului DOS), oferind utilizatorului diverse
servicii într-o formă nouă, cu o interfaţă vizuală, intuitivă. Totuşi, dezvoltarea
succesivă a versiunilor de Windows a urmărit cu consecvenţă principiul
compatibilităţii cu versiunile anterioare.
Sistemele Windows 3.0 şi 3.1 adaugă la serviciile oferite de sistemul de
operare DOS un mediu de operare grafic, cu facilităţi de multitasking. În
cazul în care o aplicaţie defectuoasă scrie în zona sistemului de operare sau a
altei aplicaţii, apare eroarea „General Protection Fault”.
Facilitatea de multitasking a sistemului Windows exploatează posibilităţile
microprocesoarelor Intel, care o oferă începând cu 80286, prin modul de lucru
protejat. În acelasi timp, le este permis utilizatorilor accesul la memoria extinsă.
Aceste sisteme lucrează pe 16 biţi, ceea ce nu este convenabil pentru memorarea
structurilor de date de dimensiuni mari. O dată cu trecerea la microprocesoare pe 32
de biţi, se încearcă trecerea la gestiunea memoriei pe 32 de biţi, care va aduce
creşterea considerabilă a performanţelor (se diminuează riscul de a nu putea folosi
memorie din cauza dimensiunii reduse a segmentelor de memorie adresabile pe 16
biţi). În acest scop, se introduc două instrumente: o bibliotecă dinamică de funcţii
(Dynamic Link Library - DLL), numită WINMEM32, care permite programatorilor
să scrie cod pentru Windows 3.0 folosind un spaţiu adresabil de 32 de biţi şi o
interfaţă de programare a lui Windows 3.1, numită WIN32s, care facilitează trecerea
spre Windows NT şi Windows ’95.
Windows 3.1 nu oferă suport de reţea, nu are clienţi de reţea integraţi dar
se poate executa pe un calculator dintr-o reţea Novell Netware, folosind
serviciile oferite de aceasta. (Windows 3.1 se poate instala într-o
configuraţie de reţea astfel încât în reţea să existe un singur exemplar,
partajabil, al sistemului iar pe staţia client să fie instalată o configuraţie
minimală, de aproximativ 300KB.)
Sistemul Windows 3.1 necesită, ca şi configuraţie hard minimală, un
procesor 80286 cu 1MB RAM dar se recomandă a se folosi un
microprocesor 80386 cu 4 MB RAM.
Windows for Workgroups 3.11 a apărut din necesitatea introducerii
suportului de reţea pentru sistemul de programe Windows. Suportul de reţea
oferit de Windows for Workgroups 3.11 (numit suport „punct la punct”)
permite partajarea resurselor unui calculator cu alţi utilizatori aflaţi în acelasi
grup de lucru. Se pot folosi eventual facilităţile unui server de reţea mai
complex (Novell Netware sau Windows NT).
Interfaţa cu utilizatorul este foarte asemănătoare cu Windows 3.1. În plus,
apare un grup de aplicaţii de reţea - Network - şi posibilitatea de a folosi un sistem

164
de mail. Se introduce o versiune îmbunătăţită a lui Clipboard Viewer, numită
Clipbook.
Pentru îmbunătăţirea accesului la disc se scrie un driver virtual de 32 de
biţi (VD) care creşte viteza de acces la resursele de reţea cu 100% şi viteza
de acces la datele de pe hard-disk cu 50% fată de Windows 3.1.
Configuraţia fizică minimală necesară lui Windows for Workgroups este
un microprocesor 80386 cu 4 MB RAM dar se recomandă 8 MB RAM.
Windows NT are două versiuni: pentru staţie de lucru (Microsoft
Windows NT Workstation) şi pentru server de reţea (Microsoft Windows
NT Advanced Server). Windows NT este un sistem de operare de tip server
de aplicaţii, adică oferă un suport puternic pentru crearea de aplicaţii
distribuite, bazate pe comunicarea client-server. De aceea, el va fi folosit cu
succes de firmele care produc sisteme de gestiune a bazelor de date.
Windows NT are numeroase îmbunătăţiri pentru utilizarea pe staţii de
lucru şi oferă mecanisme performante care asigură partajarea şi securitatea
informaţiilor. Iniţial, interfaţa cu utilizatorul a păstrat stilul Windows 3.1 dar
ulterior au apărut versiuni în stilul Windows ’95
Enumerăm în continuare caracteristicile sistemului Windows NT:
 este primul sistem de operare Windows (nu are nevoie de o copie
preinstalată DOS pentru a se lansa în execuţie);
 lucrează pe 32 de biţi şi oferă un mecanism de multitasking mai
performant decât predecesoarele lui;
 oferă un nou sistem de fişiere (NTFS) şi portabilitate pe procesoare non-
Intel;
 sistemul de securitate şi siguranţa în funcţionare constituie cea mai
importantă caracteristică a lui Windows NT. Arhitectura să oferă cea
mai bună protecţie în comparaţie cu alte sisteme de operare noi: OS/2
sau Windows ’95. Protecţia absolută a datelor şi aplicaţiilor este mai
importantă decât viteza şi principiul compatibilităţii (este incompatibil
cu anumite programe rezidente DOS);
 oferă facilităţi pentru utilizarea în reţea;
 nu are mecanismul "Plug and Play" al lui Windows ’95 (care va fi
descris mai jos) dar oferă drivere pentru majoritatea dispozitivelor
hard care ar putea fi utilizate, cu o configurare simplă.
Necesarul de memorie pentru lansarea lui Windows NT este mult mai mare
decât al celorlalte sisteme: minumum 12 MB RAM dar devine foarte competitiv la
32 MB RAM. Este un sistem costisitor dar oferă stabilitate şi protecţie.
Windows ’95 este un sistem de operare pe 32 de biţi (nu are nevoie de
MS-DOS pentru a se lansa în execuţie) care permite execuţia de aplicaţii
multithreading (cu mai multe „fire” de execuţie, care funcţionează în regim

165
de multitasking). Stilul de execuţie al aplicaţiilor DOS, pe 16 biţi şi pe 32 de
biţi este similar cu cel de sub Windows NT. Aplicaţiile native Windows ’95
sunt foarte rapide dar la Windows ’95 se pot adapta relativ uşor aplicaţii
Windows 3.1 (folosind interfaţa WIN32) şi mai ales aplicaţii Windows NT.
Un principiu de bază urmărit în proiectarea lui Windows ’95 a fost
compatibilitatea cu versiunile mai vechi: se pot executa aplicaţii MS-DOS şi
Windows pe 16 biţi, ceea ce lărgeşte semnificativ numărul de aplicaţii pe
care le pune la dispoziţia utilizatorului, oferindu-i un avantaj considerabil
faţă de alte sisteme de operare (OS/2, Unix sau Windows NT).
Interfaţa lui Windows ’95 are caracteristici proprii sistemelor orientate
obiect: la lansare apare un desktop cu diverse icon-uri, aplicaţiile care se
execută apar în bara de task-uri şi pot fi manipulate într-un mod foarte
intuitiv, folosit prima oară la Apple MacIntosh şi preluat de OS/2 Warp. În
plus, fiecărui obiect îi este asociat un meniu numit contextual, care conţine
operaţii uzuale şi poate fi accesat cu butonul din dreapta al mouse-ului.
Windows ’95 introduce un nou sistem de fişiere, prin care se pot folosi
nume de maximum 255 de caractere. Creşte calitatea şi numărul accesoriilor:
Notepad şi Character Map rămân dar Write este înlocuit cu WordPad,
Paintbrush - cu Paint, Calculator este îmbunătăţit, Calendar şi Cardfile dispar
dar apare Briefcase. Se aduc îmbunătăţiri şi în privinţa comunicărilor prin
introducerea aplicaţiei Exchange, care interacţionează cu Microsoft Mail,
Microsoft Exchange Server şi Microsoft Network.
Din punctul de vedere al posibilităţilor oferite pentru lucrul în reţea, se
remarcă faptul că Windows ’95 are o suită importantă de protocoale de reţea
(IPX/SPX, NetBEUI şi TCP/IP, care face posibilă comunicarea în Internet) şi de
drivere pentru plăcile de reţea. Accesarea calculatoarelor din reţea este foarte
uşoară folosind Network Neighborhood. Calculatorul poate lucra ca serviciu
telefonic de răspuns automat şi poate contabiliza apelurile telefonice prin interfaţa
de telefonie Microsoft.
Încadrarea facilităţilor lui Windows ’95 în noile direcţii de dezvoltare a
aplicaţiilor multimedia se realizează prin intermediul bibliotecii WinG, care
permite crearea de aplicaţii grafice cu performanţe superioare şi a interfeţei
de programare WinToon, pentru grafică şi animaţie multimedia.
Una din cele mai utile şi ambiţioase caracteristici a lui Windows ’95 este
facilitatea „Plug and Play”: prin încorporarea unui număr impresionant de
drivere, un număr mare de periferice este implicit instalat, astfel încât acestea pot
fi utilizate direct.
Necesarul hard minimal pentru Windows ’95 este un microprocesor
80386DX cu 4MB RAM dar se recomandă cel puţin un microprocesor
80486 pe 33MHz cu 8MB RAM iar pentru a executa aplicaţii simultane -

166
16MB RAM şi 75MB liberi pe hard-disk. Testele efectuate au arătat că
Windows ’95 se execută ceva mai încet decât Windows for Workgroups
3.11 pe 4MB RAM dar se comportă similar sau mai bine pe cel puţin 8MB
RAM. Windows ’95 rulează grafica mai rapid şi are accesul la disc mai lent
decât Windows for Workgroups 3.11 dar este foarte rapid şi stabil pentru
aplicaţiile native de 32 de biţi.
Windows ’98 are caracteristici similare cu Windows ’95 dar performanţe
superioare; acestea se referă în primul rând la integrarea în Internet şi
controlul aplicaţiilor deschise. Pentru instalare, este necesar cel puţin cu
procesor 80486 pe 66MHz cu 24MB RAM.
În anul 2000, firma Microsoft a lansat versiunea Windows 2000,
recomandată în primul rând pentru firme, şi prin care se încearcă combinarea
facilităţilor de integrare în Internet ale lui Windows ’98 cu securitatea lui
Windows NT, uşurinţa de utilizare a sistemului Windows 98 cu
caracteristicile de administrare, fiabilitate şi stabilitate ale lui Windows NT.
Pentru versiunile de tip server, care asigură o administrare eficientă a reţelei,
necesarul de memorie internă este mai mare decât pentru Windows 2000
Professional: minimum 128MB şi recomandat - 256MB. Problemele iniţiale
de compatibilitate a driverelor cu celelalte versiuni Windows au fost
rezolvate prin crearea unor drivere specifice. Facilităţile de acces la Internet
sunt integrate într-un pachet complet şi performant. Dedicarea versiunii
Windows 2000 Professional în special pentru afaceri este susţinută de faptul
că se tinde către reducerea costului total al utilizării sistemului, în condiţiile
asigurării unei productivităţi şi flexibilităţi ridicate.
Windows Millennium Edition (Windows Me) continuă linia de produse
Windows ’95, ’98, punând la dispoziţia utilizatorilor o serie de instrumente
noi pentru prelucrarea datelor multimedia: înregistrarea şi editarea
videofilmelor digitale, stocarea şi organizarea imaginilor, precum şi o bună
calitate a sunetului.
Trebuie de asemenea remarcate facilităţile Windows ME pentru
construirea unei mini-reţele locale de calculatoare: partajarea unei conexiuni
la Internet între mai multe calculatoare, partajarea imprimantelor, a fişierelor
de sunet şi a imaginilor. Windows Me este primul sistem de operare care
suportă standardul UPnP (Universal Plug and Play), ceea ce permite
conectarea şi deconectarea perifericelor fără a fi necesară repornirea
calculatorului, precum şi detectarea rapidă a resurselor care pot fi partajate
într-o reţea. Spre deosebire de Windows 2000, Millennium Edition este
dedicat utilizatorilor individuali (home users).
O comparaţie între sistemele Windows se poate face urmărind tabelul de
mai jos.

167
Versiunea Windows Win Win Win Win Win Win Win
3.1 3.11 NT ’95 ’98 ME 2000
Caracteristica

Interfaţa utilizator orientată Nu Nu Da Da Da Da Da


obiect

Integrarea în reţea Nu Da Da Da Da Da Da

Compatibilitate cu vechile Da Da Nu Da Da Da Relativ


aplicaţii prea

Acces pe 32 de biţi la disc Nu Da Da Da Da Da Da

Arhitectură pe 32 de biţi Nu Nu Da Da Da Da Da

Portabilitate Nu Nu Da Da Da Da Da

Stabilitate şi securitate Nu Nu Da Nu Nu prea Relativ Da

Cerinţe minime de 1MB 3MB 12MB 4MB 24MB 32MB 64MB


memorie

Cerinţe recomandate de 4MB 8MB 32MB 8MB 32MB 64MB 128 MB


memorie

Suport pentru Plug and Nu Nu Nu Da Da Da Da


Play

Interfaţa vizuală a sistemelor Windows ’9x - principii generale


Trecerea de la sistemul de operare DOS, în care se lucra la nivel de
comandă, la un sistem de operare cu o interfaţă vizuală a produs un salt
calitativ în dezvoltarea softului şi a făcut calculatoarele personale mai
accesibile pentru toti utilizatorii. Noua concepţie soft asigură o folosire
extrem de intuitivă a calculatoarelor prin intermediul unei interfeţe specifice.
Vom prezenta în continuare câteva principii de utilizare a sistemelor
Windows ’95/’98 - numite generic Windows ’9x - pentru a putea face o
comparaţie cu lucrul sub sistemul DOS.
Ecranul sistemelor Windows ’95/’98 este considerat un spaţiu de lucru -
desktop - pe care apar icon-urile (simbolurile) corespunzătoare aplicaţiilor.
Bara de task-uri conţine butonul Start care permite lansarea rapidă în execuţie

168
a unor programe sau redeschiderea rapidă a documentelor recent utilizate. Pe
bara de task-uri va apărea câte un buton pentru fiecare aplicaţie activă (de aici,
ele pot fi alese în regim de multitasking sau, echivalent, se poate folosi
combinaţia de taste Alt-Tab preluată din Windows 3.x). Opţiunile lui Start
sunt: Programs, pentru lansarea în execuţie a aplicaţiilor (această opţiune îl
înlocuieste pe Program Manager din Windows 3.x), Documents, pentru
accesarea rapidă a ultimelor documente prin deschiderea lor în editoarele
corespunzătoare, Settings, cu aplicaţii pentru setarea unor opţiuni ale
sistemului (aplicaţia Control Panel, folder-ul Printers, modificarea barei de
task-uri şi a meniului Start), Find, pentru căutarea de fişiere / foldere folosind
criterii complexe, Help, pentru lansarea în execuţie a aplicaţiei Help, Run,
pentru lansarea în execuţie a unei aplicaţii (dacă se dă o comandă) sau
deschiderea unui folder sau director (dacă acesta se specifică) într-o fereastră
numită fereastră de navigare (a se vedea mai jos tipurile de ferestre) şi Shut
Down, pentru oprirea lui Windows ’9x.
Vizualizarea elementelor calculatorului (drive-uri locale şi de reţea,
imprimante etc.) se poate realiza cu ajutorul icon-ului My Computer care,
activat, afişează elementele sub formă de icon-uri într-o fereastră. Pentru
navigarea în reţea se poate folosi Network Neighborhood iar pentru
recuperarea fişierelor şterse - Recycle Bin. Revenirea asupra unei operaţii se
poate realiza cu: opţiunea Edit - Undo, butonul Undo sau eventual opţiunea
corespunzătoare dintr-un meniu contextual.
Windows ’95 introduce notiunea de folder, care desemnează o grupare de
elemente diferite (fişiere, documente, aplicaţii sau foldere) sau, în termeni de
Windows 3.x, un grup de aplicaţii sau un director. Icon-urile pot reprezenta
foldere, fişiere sau programe, folosind pictograme specifice. Copierea şi
mutarea icon-urilor se poate realiza cu ajutorul mouse-ului ca în versiunile
Windows anterioare; aici însă, ele pot reprezenta fişiere sau foldere. Se preia,
din anterioarele versiuni Windows, stilul de operare (copiere / mutare) prin
zona de memorie Clipboard, care permite transferul unor obiecte de tipuri
diverse (fişiere, foldere, blocuri de text, imagini etc.).
În Windows ’9x se utilizează următoarele tipuri de ferestre: de navigare
(cu meniul File, Edit, View, Help - de exemplu My Computer), de explorare
(cu meniul File, Edit, View, Tools, Help - de exemplu Windows Explorer),
de aplicaţie (dacă conţin o aplicaţie deschisă), de document (într-o aplicaţie
care prelucrează documentul) sau de dialog, cu obiecte de control specifice.
Operaţiile cu ferestre sunt analoage celor din Windows 3.1x iar designul lor
este similar, cu mici modificări legate de simbolurile meniului sistem,
maximizării, minimizării (introducerea aplicaţiei în bara de task-uri) şi
închiderii ferestrelor.

169
Un mecanism foarte puternic, preluat din aplicaţiile Windows 3.1 (Word, Excel etc.),
este cel al meniurilor contextuale. Acestea sunt ataşate fiecărui obiect (icon, folder, meniu,
bara de task-uri, desktop), fiind accesibile cu butonul din dreapta al mouse-ului şi permit
realizarea unor operaţii complexe asupra elementului respectiv: copiere, mutare, ştergere,
redenumire, schimbarea caracteristicilor / proprietăţilor, crearea de obiecte noi. De
exemplu, folosind acest mecanism în Windows Explorer (succesorul lui File Manager) se
pot crea foldere (directoare) în poziţia dorită. Un alt exemplu ar fi aranjarea icon-urilor
(Arrange Icons) din meniul contextual al desktop-ului.
Shortcut-urile sunt un instrument puternic, introdus în Windows ’95 pentru
creşterea eficienţei în accesarea unor aplicaţii; ele sunt reprezentate prin icon-uri
speciale (cu o săgeată mică în coltul stânga jos). Se pot crea shortcut-uri la orice
obiect (fişier, program, folder, drive) şi se pot plasa oriunde (pe suprafaţa de
lucru, într-un folder sau într-o aplicaţie). Un dublu click pe icon-ul de shortcut are
acelaşi efect ca şi pe icon-ul corespunzător lui. Un shortcut se poate crea din
meniul File - Create Shortcut al ferestrei de navigare în care se găseşte obiectul,
din meniul contextual al obiectului (Create Shortcut) sau cu ajutorul mouse-ului
(cu tastele Ctrl-Shift apăsate sau cu opţiunea Create Shortcut(s) Here din meniul
care apare după deplasarea cu mouse-ul). Ştergerea unui shortcut (cu Delete sau
folosind icon-ul Recycle Bin) nu afectează obiectul căruia îi corespunde.
Menţionăm că shortcut-urile în folderul de programe sunt similare icon-urilor de
programe din grupurile lui Program Manager.
Utilizarea lui Windows Explorer este analoagă cu cea a lui File Manager din
Windows 3.1; în plus, meniurile contextuale permit realizarea mai uşoară a
multor operaţii (un click dublu pe un element este asociat opţiunii implicite din
meniul contextual). Marcarea elementelor se face analog cu cea din Windows 3.x
iar pentru operaţii de copiere sau mutare se pot folosi opţiunile Copy, Cut, Paste
din meniul Edit sau butoanele analoage (apariţia acestora poate fi activată /
dezactivată din View). Conţinutul unui folder se poate afişa (View) sub forma de
icon-uri sau ca listă de elemente, cu nume sau cu informaţii complete.
Pentru un nivel mai avansat de utilizare a lui Windows ’9x, se poate schimba
configuraţia meniului Start prin adăugare de submeniuri. În acest scop, se poate
folosi din meniul contextual al lui Start opţiunea Open iar apoi, din fereastra de
navigare deschisă, File - New - Folder sau Shortcut, în funcţie de necesităţi. O
altă posibilitate este de a folosi opţiunea Start - Settings - Taskbar (se pot adăuga
elemente noi cu Add sau se pot elimina elemente cu Remove).

8.3 Sistemul UNIX

Prezentare

170
UNIX a apărut în perioada anilor ‘70 (primul proiect MULTIX -
laboratoarele Bell ale societăţii AT&T) şi s-a dezvoltat la început în limbajul
B, înlocuit din 1973 de limbajul C.
Unix este un sistem multiutilizator şi multiacces care funcţionează pe
un sistem în timp partajat.
La început au fost dezvoltate două versiuni ale sistemului UNIX:
 AT&T  System III şi System V (1983);
 Universitatea Berkley  BSD 4.1, 4.2 şi 4.3.
Sistemele utilizate la ora actuală au preluat funcţionalităţi specifice din cele
două versiuni. Versiunea SunOS 4.1.3 (Solaris 1), de exemplu, care are originea
derivată din BDS 4.2, a introdus funcţionalităţi proprii: NFS Network File
System şi NIS Network Information Services, apoi a integrat funcţionalităţi
specifice versiunii System V: mesaje, semafoare, memorie partajată.
Versiunea 4.1 a adus nou standardizarea comenzilor, încărcare dinamică
a modulelor nucleului ca şi un nou tip de sistem de fişiere care permite
crearea fişierelor temporare în memoria virtuală.
Versiunea SunOS 5.0 (Solaris 2) este derivată din System V R4
(dezvoltat în colaborare de către Sun şi AT&T).
Evoluţia sistemului UNIX ar trebui să conducă până în anul 2000 la
un sistem portabil pe toate tipurile de sisteme de calcul.
Funcţiunile deja normalizate reprezintă 95% din totalul comenzilor
UNIX şi sunt conţinute în standardul XPG.

Legarea (login) pe un sistem UNIX


Există mai multe cazuri de legături:
a) legătura asincronă: este cazul cel mai răspândit, în care terminalul
este direct legat la un calculator sau la o staţie de lucru printr-o
legătură asincronă;
b) server ethernet: în acest caz, conexiunea prezintă o etapă
suplimentară care este conexiunea la calculatorul legat prin
ethernet. Avantajul acestei soluţii este o mare supleţe de utilizare,
permiţând conectarea tuturor calculatoarelor din reţea care suportă
protocolul serverului de terminale;
c) login deja stabilit: pornind de la o sesiune deja stabilită, există
posibilitatea conectării la un alt calculator prin intermediul
comenzilor rlogin şi telnet când se utilizează o reţea TCP/IP. Este
preferabilă utilizarea comenzii rlogin între maşini UNIX, dar este
obligatorie utilizarea comenzii telnet între calculatoare având
sisteme de operare diferite.

171
Comenzile sistemului de fişiere
Vom prezenta pe scurt funcţionarea următoarelor comenzi:
 % mkdir: crearea unui director;
 % rmdir: ştergerea unui director;
 % cd: schimbarea directorului curent;
 % pwd: afişarea numelui directorului curent;
 % ls: listarea fişierelor dintr-un director;
 % cp: copierea fişierelor;
 % mv: schimbarea numelui unui fişier şi/sau deplasarea în arbore;
 % ln: crearea unui inod pe un fişier;
 % rm: ştergerea unui fişier;
 % chmod: schimbarea drepturilor de acces la un fişier;
 % chown: schimbarea proprietarului unui fişier;
 % unmask: afişarea sau definirea măştii de creare a fişierelor;
 % newgrp: schimbarea grupului.
Structura fişierelor sub UNIX este arborescentă compusă din directoare
şi fişiere. O submulţime a acestei structuri poate fi reprezentată astfel:
/

bin lib etc tmp usr dev vmunix boot lost+found

adm bin include lib man spool sys users


Drepturi de acces la fişiere
Un director este considerat ca un fişier particular conţinând nume de
fişiere şi/sau numele altor directoare:
 /  caracter de separare pentru desemnarea unui fişier;
 .  reprezintă directorul curent;
 ..  reprezintă directorul părinte.
Deci nume_fişier şi . /nume_fişier reprezintă acelaşi fişier.

Fişiere
Fiecărui utilizator îi este asociat un număr numit user-id (uid). Acest uid
va fi utilizat pentru a evidenţia dreptul de proprietate asupra fişierului.

172
De asemenea, fiecare utilizator aparţine unui grup reperat printr-un
număr numit group-id (gid).
Astfel, pentru fiecare fişier există trei drepturi de acces (rwx):
 r: dreptul de citire a fişierului;
 w: dreptul de scriere şi modificare a fişierului;
 x: dreptul de execuţie a fişierului.
Aceste drepturi sunt aplicabile pentru trei clase de utilizatori:
 proprietarul fişierului (owner);
 utilizatorii membrii ai aceluiaşi grup ca şi proprietarul (group);
 toţi ceilalţi utilizatori ai sistemului (others).
owner group others
rwx rwx rwx
O bună protecţie pentru un fişier nepartajabil se poate realiza prin atribuirea
drepturilor: - r w - - - - - -, unde „-” specifică absenţa dreptului respectiv.
Directoare
Pentru un director, cheile rwx îşi schimbă semnificaţia faţă de cazul
fişierelor:
 r: dreptul de citire şi deci de listare (ls) al directorului;
 w: dreptul de scriere în director şi deci de ştergere a fişierelor pe
care le conţine;
 x: dreptul de parcurgere a directorului (cd) interzice orice operaţie
asupra directorului, cea mai bună metodă de a-l proteja faţă de alţi
utilizatori.
Comanda unmask 066 poziţionează masca de creare a fişierelor cu
valoarea octală 066 şi are ca efect crearea directoarelor cu drepturile:
r w x - - x - - x şi fişierele cu drepturile: r w - - - - - - -.

Comenzi de bază
Majoritatea comenzilor UNIX deschid 3 fişiere (unităţi logice) care sunt
asignate astfel:
 0: intrarea standard (stdin) este asociată tastaturii terminalului;
 1: ieşirea standard (stdout) este asociată ecranului terminalului
 2: ieşirea erorilor (stderr) este asociată ecranului terminalului.
O comandă care utilizează aceste dispozitive standard este numită filtru,
conform figurii următoare:

Stdin 0 Stdout 1
Comandă UNIX

173
Stderr 2
Este de asemenea posibilă redirectarea intrării şi ieşirii comenzilor către
un fişier sau către o altă comandă, prin utilizarea caracterelor >, >>, <, <<, I,
„ “.
Redirectarea ieşirii standard se realizează astfel:
% comandă > nume_fişier sau
% comandă >> nume_fişier.
În primul caz se crează fişierul sau se şterge dacă exista deja, iar în al
doilea caz se adaugă la sfârşitul fişierului specificat.
Redirectarea erorilor se face cu 2> sau 2>> în loc de > sau >>.
Redirectarea intrării standard se realizează sub forma următoare:
% comandă < nume_fişier
Redirectarea unei comenzi este numită pipe, este simbolizată prin
caracterul I sau ^, şi este reprezentată ca în figura următoare:

Stdin Stdout
Comanda Comanda Comanda
0 Unix 1 0 Unix 10 Unix 1
2 2 2

Formatul standard al unei comenzi:


% nume_comandă opţiuniargumente

Crearea şi ştergerea directoarelor: mkdir, rmdir


Un director este creat prin intermediul comenzii mkdir (make directory)
potrivit sintaxei următoare:
% mkdir nume_director
Un director vid poate fi şters prin intermediul comenzii rmdir (remove
directory) potrivit sintaxei următoare:
% rmdir nume_director

Deplasarea în arborele fişierelor: cd, pwd


Comanda cd (change directory) permite schimbarea directorului curent
potrivit sintaxei următoare:

174
% cd nume_director
Comanda pwd (print working directory) permite afişarea numelui
directorului curent potrivit sintaxei următoare:
% pwd

Listarea atributelor fişierelor şi directoarelor: ls


Comanda ls (list files) permite listarea conţinutului directoarelor:
% ls listarea directorului curent;
% ls -lg listarea directorului curent format lung;
% ls -a listarea directorului curent cu fişierele „ascunse” ;
% ls nume listarea directorului cu numele specificat;

Definire mască de creare a fişierelor: unmask


Comanda unmask permite poziţionarea unei măşti definind drepturile de
acces la fişiere la crearea acestora. Masca este complementul faţă de 1 a
drepturilor dorite şi se exprimă de regulă în octal.

Exemplu:
rwx - -x - - x simboluri de drepturi;
111 001 0 0 1 drepturi în binar: 711 în octal;
000 110 1 1 0 mască în binar; 066 în octal;
% unmask 066 poziţionare mască;
% unmask afişare mască
066

Schimbarea drepturilor de acces la fişiere: chmod


Comanda chmod (change mode) modifică drepturile de acces la fişiere şi
directoare, potrivit sintaxei următoare:
% chmod ugoa drepturi de schimbat fişiere
Exemplu: se doreşte ca pentru fişierul cu numele toto să se atribuie
drepturile: r w x r - x r - x, sau 754 în octal, sau 111 101 101 în binar:
% chmod 754 toto

Schimbarea proprietarului de fişiere sau director: chown


Comanda chown (change ownwr) permite schimbarea proprietarului
unui fişier potrivit următoarei sintaxe:
% chown - R proprietar_fişiere
Exemplul 1: se doreşte trecerea fişierului toto în proprietatea
utilizatorului paul:
% chown paul toto

175
Exemplul 2: se doreşte trecerea directorului reper şi a tuturor fişierelor
sale în proprietatea utilizatorului paul:
% chown - R paul reper

Schimbarea grupului de fişiere sau director: chgrp


Comanda chgrp (change group) permite schimbarea grupului unui fişier
potrivit aceleiaşi sintaxe ca şi la comanda chown.

Creare inod pe un fişier: ln


Comanda ln permite crearea unui inod pe un fişier. Un inod este de fapt
definirea unui al doilea nume pentru un fişier deja existent.
 inoduri hard: un acelaşi fişier fizic va căpăta mai multe nume de
acces, ceea ce va facilita partajarea fişierului;
% ls -l
- r w x r w - r w - 2 / user 512 1033 toto
Fişierul toto are aici 2 accese. Pentru crearea unui inod:
% ln fişier1 fişier2
Observaţie: un director are întotdeauna directorul . ca inod, ca şi
toate subdirectoarele sale.
 inoduri soft:
% ln - s fişier1 fişier2
Fişierul fişier2 va fi o referinţă a fişierului fişier1. Numărul de
inod nu este modificat, existenţa unui fişier este legată de
existenţa celuilalt.

Copierea fişierelor sau directoarelor: cp


Comanda cp (copy) permite copierea fişierelor potrivit sintaxei:
% cp - irp fişier1 fişier2 . . . fişiern, unde opţiunea -r permite
recursivitatea comenzii.
Exemplul 1: se doreşte copierea fişierului toto din directorul său curent,
în fişierul tata din directorul său curent:
% cp toto tata
Exemplul 2: se doreşte copierea fişierului toto din directorul /usr/lib, în
fişierul toto din directorul său curent:
% cp /usr/lib/toto .
Exemplul 3: se doreşte directorului toto al directorului /usr/lib, în subdirectorul
directorului său curent împreună cu toată arborescenţa lui /usr/lib/toto:
% cp -r /usr/lib/toto .

Ştergerea fişierelor: rm

176
Comanda rm (remove) permite ştergerea fişierelor potrivit sintaxei:
% rm - irf fişier1 fişier2 . . . fişiern
Opţiunile din comandă au următoarea semnificaţie:
 -i: mod de lucru interactiv (confirmare înaintea ştergerii);
 -r: pentru un director se realizează ştergerea recursivă a tuturor
fişierelor sale ca şi a subdirectoarelor pe care le conţine;
 -f: dacă fişierul este inexistent nu apare mesaj de eroare, iar dacă nu
există dreptul w, nu se cere confirmarea ştergerii.

Redenumirea fişierelor şi a directoarelor: mv


Comanda mv (move) permite redenumirea unui fişier sau deplasarea
acestuia în arborescenţă, potrivit sintaxei următoare:
% mv - if fişier1 fişier2 . . . fişiern dir1

Concatenare fişiere: cat


Această comandă este un filtru care permite filtrarea şi concatenarea
fişierelor potrivit sintaxei următoare:
% cat -nv
Opţiunile din comandă au semnificaţia:
 - n permite numerotarea liniilor;
 - v permite transformarea (filtrarea) caracterelor neimprimabile sub
o formă imprimabilă. Astfel, caracterele de control sunt imprimate
sub forma ^x (CTRL/C = ^C) şi caracterele ASCII sub forma M-x.
Exemplu: se concatenează fişierele alfa.c şi beta.c în gama.c:
% cat alfa.c beta.c >gama.c

Afişare pagină cu pagină a fişierelor pe ecran: more sau page


Această comandă permite afişarea pagină cu pagină. Apăsarea tastei
<ENTER> realizează deplasarea unei linii, iar apăsarea tastei <SPAŢIU>
realizează defilarea cu un ecran.
h afişează helpul comenzii more;
v lansează editorul vi pe linia curentă.
Compararea fişierelor: cmp
Sintaxa comenzii este:
% cmp - l - s fişier1 fişier2
Pentru a afişa toate diferenţele se utilizează opţiunea - l care produce un
tablou pe 3 coloane (1 pentru poziţia caracterului în fişier şi celelalte 2
pentru caractere).
Pentru compararea fişierelor ASCII se poate utiliza comanda diff.

177
Interpretoare de comenzi
Există trei interpretoare de comenzi: Bourne Shell, C-Shell şi Korn Shell.
De regulă sunt executate trei tipuri de comenzi:
a) comenzi interne care fac parte din shell (înainte de crearea procesului):
 comenzi foarte frecvente: cd, pwd, umask, ...;
 directive algoritmice: if, then, else, while, case, for, ...
b) comenzi externe conţinute în directoare (după crearea unui nou proces);
c) comenzi create prin funcţii shell.
Execuţia unei comenzi poate fi de mai multe feluri:
a) interactivă: comanda este lansată la terminal şi controlul este
returnat sistemului la terminarea acesteia;
b) asincronă (background): pentru execuţia unei compilări sau a unei
comenzi al cărei rezultat poate întârzia. Comanda este lansată
urmată de caracterul &;
c) înregistrată: lansată cu at, permite declanşarea execuţiei unui fişier
de comenzi la o dată specificată;
d) batch: lansată cu comanda batch (System V), crează o coadă de
aşteptare , iar fişierul se lansează când ajunge în capul cozii;
e) ciclică: este lansată cu comanda crontab (System V).

Editorul de texte vi
Acest editor posedă două moduri de lucru:
a) modul comandă (MC);
b) modul inserare (MI).
În modul inserare, cele mai importante comenzi sunt i (insert) sau a
(append), iar ieşirea din modul inserare se realizează prin apăsarea
tastei<ESCAPE>.
Modul comandă posedă două tipuri de comenzi:
a) comenzi care rămân în MC după execuţie;
b) comenzi care părăsesc MC şi fac să se treacă în MI.

Poşta electronică
Comanda mail este utilizată pentru emisia şi recepţia curierului
electronic între utilizatori. Un mesaj poate fi transmis către unul sau mai
mulţi utilizatori.

Salvare şi arhivare
Datele utilizate într-o reţea pot fi salvate pe dischetă cu ajutorul comenzii bar.

Execuţie la distanţă, transfer de fişiere la distanţă

178
Comanda rsh permite execuţia unei comenzi pe un sistem de calcul la
distanţă (în anumite condiţii).
Comenzile rcp şi ftp permit transferul fişierelor între un nod local şi un
nod la distanţă, acţiune care necesită existenţa unor fişiere speciale care
realizează conectarea şi transferul propriu-zis.

X - Windows
X-Windows este un sistem de interacţiune cu utilizatorul, orientat spre
ferestre, care poate fi operaţional pe o mare varietate de sisteme de calcul
care lucrează sub sisteme de operare diferite.
În esenţă, sistemul X-Windows reprezintă o interfaţă utilizator grafică
(GUI) prin intermediul căreia se realizează independenţa faţă de sistemul de
operare şi de echipamentul hardware.
Scopul sistemului X-Windows este acela de a furniza programelor de
aplicaţie un mediu de lucru independent de particularităţile staţiei de lucru, a
sistemului de operare, a reţelei în care este integrat etc.
9. APLICAŢII JAVA

9.1 Conversie din zecimal în binar, octal, hexazecimal

import java.io.*;

/*
Fie N un număr natural dat.
 Să se citească repetat şi să se valideze N;
 Să se calculeze corespondentul binar, octal, hexazecimal al lui N;
 Să se afişeze cifrele numerelor astfel obţinute.
**/
class Reprezentare
{
public static void main (String argv[])
{
while (true){
InputStreamReader stdin = new
InputStreamReader(System.in);
BufferedReader console = new BufferedReader(stdin);
int N;
int N_valid;

179
String s1,s2;
//N_valid = Integer.parseInt(argv[0]); //numarul este
dat ca argument in linia de comanda
N_valid = 203;
try
{
System.out.print("N = ");
s1 = console.readLine();
N = Integer.parseInt(s1);
if (N != N_valid)
System.out.println("Numar invalid: introduceti un alt numar");
else
{
System.out.println("Reprezentarea in binar a numarului "
+ N + " este " + binar(N));
System.out.println("Reprezentarea in octal a numarului "
+ N + " este " + octal(N));
System.out.println("Reprezentarea in hexazecimal a
numarului " + N + " este " + hexazecimal(N));
}
}
catch(IOException ioex)
{
System.out.println("Eroare la intrare");
System.exit(1);
}
catch(NumberFormatException nfex)
{
System.out.println("\"" + nfex.getMessage() + "\" nu este un numar");
System.exit(1);
}
}
}

public static long binar(int n)


{
int rez = 0;
int i;
int temp[];
temp = new int[100];

180
i = 0;
if(n<=0) return(0);
while (n>0){
temp[i] = n % 2;
n = n/2;
i++;
}
for(int j = i-1;j>=0;j--)
rez = rez * 10 + temp[j];

return rez;
}
public static long octal(int n)
{
int rez = 0;
int i;
int temp[];
temp = new int[100];
i = 0;
if(n<=0) return(0);
while (n>0){
temp[i] = n % 8;
n = n/8;
i++;
}
for(int j = i;j>=0;j--)
rez = rez * 10 + temp[j];
return rez;
}
public static String hexazecimal(int n)
{
int rez = 0;
int i;
int temp[];
String s;
char aux;
s = "";
temp = new int[100];
i = 0;
if(n<=0) return Integer.toString(0);

181
while (n>0){
temp[i] = n % 16;
n = n/16;
i++;
}
for(int j = i-1;j>=0;j--)
if (temp[j] < 10)
s = s + temp[j];
else {
temp[j] = 'A' + (temp[j] - 10);
aux = (char)temp[j];
s = s + aux ;
}
return s;
}
}

9.2 Reprezentări externe ale unui număr întreg

import java.io.*;

/*
Fie m numărul de cifre pentru a = (am, am-1, .., a0) în reprezentare internă
(în sistemul binar).
 Să se citească şi să se valideze m şi a;
 Să se stabilească reprezentările externe posibile ale lui a;
 Să se afişeze aceste reprezentări.
*/
class ExDoi
{
public static void main (String argv[])
{

while (true){
InputStreamReader stdin = new
InputStreamReader(System.in);
BufferedReader console = new BufferedReader(stdin);
int a, m;
182
String s1, s2;
try
{
System.out.print("m = ");
s1 = console.readLine();
m = Integer.parseInt(s1);
if (m <= 0)
{
System.out.println("Numar de cifre invalid");
System.exit(1);

}
System.out.print("a = ");
s2 = console.readLine();
a = Integer.parseInt(s2);
if (a <= 0)
{
System.out.println("Numar binar invalid");
System.exit(1);
}
if (verificare(a,m,2) != 0)
{
System.out.println("Numar binar invalid");
System.exit(1);
}
System.out.println("Reprezentarea externa ca intreg a numarului
" + a + " este " + reprezentare_b(a,2));
System.out.println("Reprezentarea externa ca si caracter a numarului
" + a + " este " + (char)reprezentare_b(a,2));

}
catch(IOException ioex)
{
System.out.println("Eroare la intrare");
System.exit(1);
}
catch(NumberFormatException nfex)
{
System.out.println("\"" + nfex.getMessage() + "\" nu este un numar");
System.exit(1);

183
}
}
}

//functie de verificare validitate a numarului n, de m cifre, scris in baza p


public static int verificare(int n, int m, int p)
{
int i;
if(n < 0)
return -1;
i = 0;
//daca reprezentarea zecimala a numarului n
if(reprezentare_b(n, 2) > (int)(Math.pow((double) p, (double) m) - 1))
{
return -1;
}
while (n>0){
if ((n%10) >= p || (n%10) < 0)
return -1;
n = n/10;
i++;
}
return 0;
}
public static long reprezentare_b(int n, int baza)
{
int rez = 0;
int i;
int temp[];
temp = new int[100];
i = 0;
if(n<=0) return 0;
while (n>0){
temp[i] = n % 10;
n = n/10;
i++;
}
for(int j = i-1;j>=0;j--)
rez = rez * baza + temp[j];
return rez;

184
}
}

9.3 Suma a două numere în baza p

import java.io.*;

class ExTrei
{
public static void main (String argv[])
{
while (true){
InputStreamReader stdin = new
InputStreamReader(System.in);
BufferedReader console = new BufferedReader(stdin);
int a, b, p, m, n;
String baza, s1, s2;
try
{
System.out.print("p = ");
baza = console.readLine();
p = Integer.parseInt(baza);
if (p <= 1 || p > 9)

185
{
System.out.println("Baza de numeratie invalida");
System.exit(1);
}
System.out.print("m = ");
s1 = console.readLine();
m = Integer.parseInt(s1);
if (m <= 0)
{
System.out.println("Numar de cifre invalid");
System.exit(1);

}
System.out.print("a = ");
s2 = console.readLine();
a = Integer.parseInt(s2);
if (a < 0)
{
System.out.println("Numar invalid");
System.exit(1);
}
if (verificare(a, m, p) != 0)
{
System.out.println("Numar invalid in baza " + p);
System.exit(1);
}
System.out.print("n = ");
s1 = console.readLine();
n = Integer.parseInt(s1);
if (n <= 0)
{
System.out.println("Numar de cifre invalid");
System.exit(1);
}
System.out.print("b = ");
s2 = console.readLine();
b = Integer.parseInt(s2);
if (b < 0)
{
System.out.println("Numar invalid");

186
System.exit(1);
}
if (verificare(b, n, p) != 0)
{
System.out.println("Numar invalid in baza " + p);
System.exit(1);
}

System.out.println("Adunarea celor doua numere


are ca rezultat " + adunare(a, b, m, n, p));
}
catch(IOException ioex)
{
System.out.println("Eroare la intrare");
System.exit(1);
}
catch(NumberFormatException nfex)
{
System.out.println("\"" + nfex.getMessage() + "\"
nu este un numar");
System.exit(1);
}
}
}

public static int verificare(int n, int m, int p)


{
int i;
if(n < 0)
return -1;
i = 0;
if(reprezentare_b(n,p) > (int)(Math.pow((double) p,
(double) m) - 1))
{
return -1;
}
while (n>0){
if ((n%10) >= p || (n%10) < 0)
return -1;
n = n/10;

187
i++;
}
return 0;
}
public static long reprezentare_b(int n, int baza)
{
int rez = 0;
int i;
int temp[];
temp = new int[100];
i = 0;
if(n<=0) return 0;
while (n>0){
temp[i] = n % 10;
n = n/10;
i++;
}
for(int j = i-1;j>=0;j--)
rez = rez * baza + temp[j];
return rez;
}
public static long adunare(int a, int b, int m, int n, int p)
{
int rez = 0;
int i;
int temp[];
int carry;
temp = new int[100];
i = 0;
carry = 0;
if (n >= m){
while ((a>0) || carry !=0 ){
temp[i] = (a % 10 + b % 10 + carry) % p ;
carry = ((a % 10 + b % 10 + carry) / p);
a = a/10;
b = b/10;
i++;
}
for(int j = i-1;j>=0;j--)
rez = rez * 10 + temp[j];

188
}
else{
while ((b>0) || carry !=0 ){
temp[i] = (a % 10 + b % 10 + carry) % p ;
carry = ((a % 10 + b % 10 + carry) / p);
a = a/10;
b = b/10;
i++;
}
for(int j = i-1;j>=0;j--)
rez = rez * 10 + temp[j];
}
return rez;
}
}

9.4 Diferenţa a două numere în baza p

import java.io.*;
class ExPatru
{
public static void main (String argv[])
{
while (true){
InputStreamReader stdin = new
InputStreamReader(System.in);
BufferedReader console = new BufferedReader(stdin);
int a, b, p, m, n;
String baza, s1, s2;
try
{
//mai intai citesc baza p
System.out.print("p = ");

189
baza = console.readLine();
p = Integer.parseInt(baza);
if (p <= 1 || p > 9)
{
System.out.println("Baza de numeratie invalida");
System.exit(1);
}
//apoi citesc numarul de cifre m al lui a
System.out.print("m = ");
s1 = console.readLine();
m = Integer.parseInt(s1);
if (m <= 0)
{
System.out.println("Numar de cifre invalid");
System.exit(1);
}
System.out.print("a = ");
s2 = console.readLine();
a = Integer.parseInt(s2);
//apoi citesc numarul a
if (a < 0)
{
System.out.println("Numar invalid");
System.exit(1);
}
//verific corectitudinea numarului a in baza p
if (verificare(a, m, p) != 0)
{
System.out.println("Numar invalid in baza " +p);
System.exit(1);
}
//apoi citesc numarul de cifre n al lui b
System.out.print("n = ");
s1 = console.readLine();
n = Integer.parseInt(s1);
if (n <= 0)
{
System.out.println("Numar de cifre invalid");
System.exit(1);
}

190
//apoi citesc numarul b
System.out.print("b = ");
s2 = console.readLine();
b = Integer.parseInt(s2);
if (b < 0)
{
System.out.println("Numar invalid");
System.exit(1);
}
//verific corectitudinea numarului a in baza p
if (verificare(b, n, p) != 0)
{
System.out.println("Numar invalid in baza " +p);
System.exit(1);
}
System.out.println("Scaderea celor doua numere
are ca rezultat " + scadere(a, b, m, n, p));
}
catch(IOException ioex)
{
System.out.println("Eroare la intrare");
System.exit(1);
}
catch(NumberFormatException nfex)
{
System.out.println("\"" + nfex.getMessage() + "\" nu este un numar");
System.exit(1);
}
}
}
public static int verificare(int n, int m, int p)
{
int i;
if(n < 0)
return -1;
i = 0;
if(reprezentare_b(n,p) > (int)(Math.pow((double) p,
(double) m) - 1))
{
return -1;

191
}
while (n>0){
if ((n%10) >= p || (n%10) < 0)
return -1;
n = n/10;
i++;
}
return 0;
}
public static long reprezentare_b(int n, int baza)
{
int rez = 0;
int i;
int temp[];
temp = new int[100];
i = 0;
if(n<=0) return 0;
while (n>0){
temp[i] = n % 10;
n = n/10;
i++;
}
for(int j = i-1;j>=0;j--)
rez = rez * baza + temp[j];
return rez;
}
public static long scadere(int a, int b, int m, int n, int p)
{
int rez = 0;
int i;
int temp[];
int scad;
temp = new int[100];
i = 0;
scad = 0;
if ((a > b)){
while ((b>0)){
if (a % 10 < b %10){
temp[i] = (a % 10 + p - b % 10);
scad = 1;

192
}
else {
scad = 0;
temp[i] = (a % 10 - b % 10);
}
a = a/10 - scad;
b = b/10;
i++;
}
while (a > 0){
temp[i] = a % 10;
a = a/10 - scad;
scad = 0;
i++;
}
for(int j = i-1;j>=0;j--)
rez = rez * 10 + temp[j];
}
else
return -1;
return rez;
}
}

9.5 Produsul a două numere în baza p

import java.io.*;

/*
Fie p baza unui sistem de numeraţie şi m numărul de cifre pentru
a = (am, am-1, …, a0) şi b = (bn, bn-1, ..., b0), scrise în baza p.
 Să se citească şi să se valideze m, n, p, a şi b;
 Să se calculeze produsul a × b în baza p;
 Să se afişeze acest produs.
*/
class ExCinci
{
public static void main (String argv[])
193
{

int a[], b[];


int p, m, n, c[], i, k, mult = 0, addt = 0, j;
int x,w;
String baza, s1= "", s2 = "", w1;
c = new int [100];
a = new int [100];
b = new int [100];

while (true){

InputStreamReader stdin = new


InputStreamReader(System.in);
BufferedReader console = new BufferedReader(stdin);
try
{
System.out.print("Dati ");
//mai intai citesc baza p
System.out.print("p = ");
baza = console.readLine();
p = Integer.parseInt(baza);
if (p < 2 || p > 16)
{
System.out.println("Baza de numeratie invalida");
System.exit(1);

}
//apoi citesc numarul de cifre m al lui a
System.out.print("m = ");
s1 = console.readLine();
m = Integer.parseInt(s1);
if (m <= 0)
{
System.out.println("Numar de cifre invalid");
System.exit(1);
}
//apoi citesc numarul a
for (i = m-1; i >= 0; i--){
System.out.print("a[" + i + "] = ");

194
// citesc numarul a[i], a i-a cifra a numarului a
s2 = console.readLine();
a[i] = Integer.parseInt(s2);
}

for (i = m-1; i >= 0; i--){


//verific corectitudinea numarului a in baza p
if ((a[i] < 0) || (a[i] >= p))
{
System.out.println("Numar invalid");
System.exit(1);
}
}
//apoi citesc numarul de cifre n al lui b
System.out.print("n = ");
s1 = console.readLine();
n = Integer.parseInt(s1);
if (n <= 0)
{
System.out.println("Numar de cifre invalid");
System.exit(1);
}
//apoi citesc numarul b
for (i = n-1; i >= 0; i--){
System.out.print("b[" + i + "] = ");
// citesc numarul b[i], a i-a cifra a numarului b
s2 = console.readLine();
Integer.parseInt(s2);
b[i] = Integer.parseInt(s2);
}
for (i = n-1; i >= 0; i--){
//verific corectitudinea numarului b in baza p
if ((b[i] < 0) || (b[i] >= p))
{
System.out.println("Numar invalid");
System.exit(1);
}
}
k = m + n + 1;
for (i = 0; i < k; i++)

195
c[i] = 0;
for (i = 0; i < n; i++){
if (b[i] != 0){
mult = 0;
addt = 0;
}
for (j = 0; j < m; j++){
w =a[j] * b[i] + mult;
mult = w / p;
w = w % p;
w = c[i+j] + w + addt;
addt = w / p;
c[i+j] = w % p;
}
c[i+m+1] = mult + addt;
}
while ((k<0) && (c[k] == 0))
k ++;
System.out.println("Produsul celor doua numere are ca rezultat: ");
for (i = k; i >= 0; i--)
System.out.print(c[i]);
System.out.println(" ");

}
catch(IOException ioex)
{
System.out.println("Eroare la intrare");
System.exit(1);
}
catch(NumberFormatException nfex)
{
System.out.println("\"" + nfex.getMessage() + "\" nu este numar");
System.exit(1);
}
}
}
}

196
9.6 Conversia în zecimal a unui număr reprezentat în baza p

import java.io.*;

/*
Fie p baza unui sistem de numeraţie şi m numărul de cifre pentru a = (a m,
am-1, …, a0) scris în baza p.
 Să se citească şi să se valideze m, p şi a;
 Să se convertească în sistemul zecimal;
 Să se afiseze numărul obtinut.
*/
class ExSase
{

197
char []S = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};

public static String vi (int k){


char rez = 0;
switch (k) {
case 0: rez = '0'; break;
case 1: rez = '1'; break;
case 2: rez = '2'; break;
case 3: rez = '3'; break;
case 4: rez = '4'; break;
case 5: rez = '5'; break;
case 6: rez = '6'; break;
case 7: rez = '7'; break;
case 8: rez = '8'; break;
case 9: rez = '9'; break;
case 10: rez = 'A'; break;
case 11: rez = 'B'; break;
case 12: rez = 'C'; break;
case 13: rez = 'D'; break;
case 14: rez = 'E'; break;
case 15: rez = 'F'; break;
default: System.out.println("Not a valid number"); rez = '.';
break;
}

return rez + "";

}
public static int v(char k){
int rez = 0;
switch (k) {
case '0': rez = 0; break;
case '1': rez = 1; break;
case '2': rez = 2; break;
case '3': rez = 3; break;
case '4': rez = 4; break;
case '5': rez = 5; break;
case '6': rez = 6; break;
case '7': rez = 7; break;
case '8': rez = 8; break;

198
case '9': rez = 9; break;
case 'A': rez = 10; break;
case 'B': rez = 11; break;
case 'C': rez = 12; break;
case 'D': rez = 13; break;
case 'E': rez = 14; break;
case 'F': rez = 15; break;
default: System.out.println("Not a character"); rez = -1;
break;
}

return rez;

public static void main (String argv[])


{

int a[];
int p, m, n, i, k, suma = 0, pr, j;
String baza, s1= "", s2 = "", w1;
a = new int [100];

while (true){

InputStreamReader stdin = new


InputStreamReader(System.in);
BufferedReader console = new BufferedReader(stdin);
try
{
System.out.print("Dati ");
//mai intai citesc baza p
System.out.print("p = ");
baza = console.readLine();
p = Integer.parseInt(baza);
if (p < 2 || p > 16)
{
System.out.println("Baza de numeratie invalida");
System.exit(1);

199
}
//apoi citesc numarul de cifre m al lui a
System.out.print("Numarul de cifre m = ");
s1 = console.readLine();
m = Integer.parseInt(s1);
if (m <= 0)
{
System.out.println("Numar de cifre invalid");
System.exit(1);

}
//apoi citesc numarul a
for (i = m-1; i >= 0; i--){
System.out.print("a[" + i + "] = ");
// citesc numarul a[i], a i-a cifra a numarului a
s2 = console.readLine();
a[i] = v(s2.charAt(0));
}

for (i = m-1; i >= 0; i--){


//verific corectitudinea numarului a in baza p
if ((a[i] < 0) || (a[i] >= p))
{
System.out.println("Numar invalid");
System.exit(1);

}
}
suma = 0;
pr = 1;
for (i = 0; i < m; i++){
suma = suma + pr * a[i];
pr = pr*p;
}
System.out.println("Numarul are ca rezultat in baza 10: ");
System.out.print(suma);
System.out.println(" ");

}
catch(IOException ioex)

200
{
System.out.println("Eroare la intrare");
System.exit(1);
}
catch(NumberFormatException nfex)
{
System.out.println("\"" + nfex.getMessage() + "\"
nu este un numar");
System.exit(1);
}
}
}
}

9.7 Conversia unui număr zecimal în baza p

import java.io.*;

/*
Fie N un număr în sistemul zecimal şi p  10 baza unui sistem de
numeratie.
– Să se citească şi să se valideze N şi p;
– Să se convertească N în baza p;
– Să se afiseze lista cifrelor acestui număr.
*/

201
class sapte
{
char []S = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};

public static String vi (int k){


char rez = 0;
switch (k) {
case 0: rez = '0'; break;
case 1: rez = '1'; break;
case 2: rez = '2'; break;
case 3: rez = '3'; break;
case 4: rez = '4'; break;
case 5: rez = '5'; break;
case 6: rez = '6'; break;
case 7: rez = '7'; break;
case 8: rez = '8'; break;
case 9: rez = '9'; break;
case 10: rez = 'A'; break;
case 11: rez = 'B'; break;
case 12: rez = 'C'; break;
case 13: rez = 'D'; break;
case 14: rez = 'E'; break;
case 15: rez = 'F'; break;
default: System.out.println("Not a valid number"); rez = '.';
break;
}

return rez + "";

public static int v(char k){


int rez = 0;
switch (k) {
case '0': rez = 0; break;
case '1': rez = 1; break;
case '2': rez = 2; break;
case '3': rez = 3; break;
case '4': rez = 4; break;
case '5': rez = 5; break;

202
case '6': rez = 6; break;
case '7': rez = 7; break;
case '8': rez = 8; break;
case '9': rez = 9; break;
case 'A': rez = 10; break;
case 'B': rez = 11; break;
case 'C': rez = 12; break;
case 'D': rez = 13; break;
case 'E': rez = 14; break;
case 'F': rez = 15; break;
default: System.out.println("Not a character"); rez = -1;
break;
}

return rez;

public static void baza1(int p, int ni){


int s [], i,k;
s = new int [100];
i = -1;
while (ni>0) {
i++;
s[i] = ni % p;
ni = ni / p;
}
if (i==0)
System.out.println(s[i]);
else
for (k = i; k >= 0; k--)
System.out.print(vi(s[k]));
System.out.println(" ");

}
public static void baza2(int p, float nr){
int s [], i,k;
s = new int [100];
k = 0;
while (nr != 0){

203
k++;
s[k] = (int)(p*nr);
nr = (p*nr) - s[k];
}
if (k>=1)
System.out.println(",");
for (i=1; i<k; i++)
System.out.print(""+ vi(s[i]));
System.out.println(" ");
}
public static void main (String argv[])
{

int a[];
int p, m, n, i, k, suma = 0, pr, j;
float nr;
String baza, s1= "", s2 = "", w1;
a = new int [100];

while (true){

InputStreamReader stdin = new


InputStreamReader(System.in);
BufferedReader console = new BufferedReader(stdin);
try
{
System.out.print("Introduceti nr. real n= ");
s1 = console.readLine();
nr = Float.parseFloat(s1);
if (nr < 0)
{
System.out.println("Numar invalid");
System.exit(1);

}
//apoi citesc baza p
System.out.print("p = ");
baza = console.readLine();
p = Integer.parseInt(baza);
if (p < 2 || p > 16)

204
{
System.out.println("Baza de numeratie invalida");
System.exit(1);

}
n = (int)nr;
nr = nr - n;
baza1(p,n);
baza2(p,nr);

}
catch(IOException ioex)
{
System.out.println("Eroare la intrare");
System.exit(1);
}
catch(NumberFormatException nfex)
{
System.out.println("\"" + nfex.getMessage() + "\"
nu este un numar");
System.exit(1);
}
}
}
}

9.8 Construirea unui careu magic de ordin impar

import java.io.*;

/*
Fie N un număr natural impar dat.
 Să se citească repetat şi să se valideze N;
 Să se construiască un careu magic de ordinul N;
 Să se afiseze acest careu evidenţiind şi constanta magică.

205
*/
class opt
{
public static void main (String argv[])
{

int a[][];
int n, m1, m2, i, j, k;
float nr;
String baza, s1= "", s2 = "", w1;
a = new int [20][20];

InputStreamReader stdin = new


InputStreamReader(System.in);
BufferedReader console = new BufferedReader(stdin);
try
{
System.out.println("Se construieste un careu magic cu n linii");
System.out.println("Introduceti nr. impar n, intre 1 şi 19: ");
s1 = console.readLine();
n = Integer.parseInt(s1);
if ((n < 0) || (n > 19) || (n%2 == 0))
{
System.out.println("Numar invalid");
System.exit(1);
}
for (i=1; i<n; i++)
for (j=1; j<n; j++)
a[i][j] = 0;
i = (n/2) + 2;
j = (n/2) + 1;
for (k = 1; k < n*n; k++){
a[i][j] = k;
m1 = i+1;
m2 = j+1;
if (m1 == n+1)
m1 = 1;
if (m2 == n+1)
m2 = 1;
if (a[m1][m2] == 0) {

206
i = m1;
j = m2;
}
else{
i = i+2;
if (i>n) i = i-n;
}
}
System.out.println("Careul magic este:");
for (i = 1; i < n; i++){
for (j = 1; j < n; j++)
System.out.print(a[i][j]+ " ");
System.out.println("");
}
System.out.println("");
System.out.println("Suma magica = "+ (n*(n*n+1) / 2) + " ");

}
catch(IOException ioex)
{
System.out.println("Eroare la intrare");
System.exit(1);
}
catch(NumberFormatException nfex)
{
System.out.println("\"" + nfex.getMessage() + "\" nu
este un numar");
System.exit(1);
}
}
}

9.9 Conversie din sistemul roman în sistemul arab

import java.io.*;
/*
Fie R un număr scris cu cifre romane.
 Să se citească şi să se valideze R;
 Să se calculeze corespondentul lui R în scriere cu cifre zecimale;
 Să se afişeze acest număr.
207
*/
class noua
{
public static void main (String argv[])
{
char cifra;
int i, n = 0;
boolean corect;
String s1;
int val_prec = 0, val_urm = 0;
InputStreamReader stdin = new
InputStreamReader(System.in);
BufferedReader console = new BufferedReader(stdin);
try
{
System.out.println("Numarul din cifre romane:");
s1 = console.readLine();
corect = true;
switch (s1.charAt(0)){
case 'M': val_prec = 1000; break;
case 'D': val_prec = 500; break;
case 'C': val_prec = 100; break;
case 'L': val_prec = 50; break;
case 'X': val_prec = 10; break;
case 'V': val_prec = 5; break;
case 'I': val_prec = 1; break;
default: corect = false; break;
}
if (corect == false){
System.out.println("Numar in cifre romane incorect!");
System.exit(0);
}
i = 1;
while ((corect == true) && (i < s1.length())){
switch (s1.charAt(i)){
case 'M': val_urm = 1000; break;
case 'D': val_urm = 500; break;
case 'C': val_urm = 100; break;
case 'L': val_urm = 50; break;
case 'X': val_urm = 10; break;

208
case 'V': val_urm = 5; break;
case 'I': val_urm = 1; break;
default: corect = false; break;
}
if (val_prec < val_urm){
n = n - val_prec;
}
else
n = n + val_prec;
val_prec = val_urm;
i++;
}
if (corect == true)
System.out.println("Numarul in scriere araba:" +
(n+val_prec));
else
System.out.println("Eroare: " + s1.charAt(i)+ " nu
este cifra romana");
}
catch(IOException ioex)
{
System.out.println("Eroare la intrare");
System.exit(1);
}
catch(NumberFormatException nfex)
{
System.out.println("\"" + nfex.getMessage() + "\" nu
este un numar");
System.exit(1);
}
}
}

9.10 Conversie din sistemul arab în sistemul roman

import java.io.*;

/*
Fie N un număr natural dat.
 Să se citească repetat şi să se valideze N;
209
 Să se exprime în sistemul roman toate puterile lui 2 de la 1 până la N;
 Să se afiseze aceste numere.
*/
class zece
{
public static void main (String argv[])
{

int x,y;

y = 1;
System.out.print("Program pentru exprimare a puterilor lui 2
in cifre romane:");
while (y <= 5000){
x = y;
System.out.print(y + " : ");
while (x > 1000){
System.out.print("M");
x = x - 1000;
}
if (x >= 900){
System.out.print("CM");
x = x-900;
}
if (x >= 500){
System.out.print("D");
x = x-500;
}
if (x >= 400){
System.out.print("CD");
x = x-400;
}
while (x >= 100){
System.out.print("C");
x = x - 100;
}
if (x >= 90){
System.out.print("XC");
x = x-90;
}

210
if (x >= 50){
System.out.print("L");
x = x-50;
}
if (x >= 40){
System.out.print("XL");
x = x-40;
}
while (x >= 10){
System.out.print("X");
x = x - 10;
}
if (x >= 9){
System.out.print("IX");
x = x-9;
}
if (x >= 5){
System.out.print("V");
x = x-5;
}
if (x >= 4){
System.out.print("IV");
x = x-4;
}
while (x >= 1){
System.out.print("I");
x = x - 1;
}
y = 2*y;
System.out.println(" ");
}
}
}

9.11 Numere de trei cifre egale cu suma cuburilor cifrelor lor

import java.io.*;

/*
Fie N un număr zecimal de trei cifre.
211
 Să se citească repetat şi să se valideze N;
 Să se dacă N este egal cu suma cuburilor cifrelor sale
 Să se afiseze toate numerele cu proprietatea dată.
*/
class unusprezece
{
public static void main (String argv[])
{

int n, n1, a, b, c;
boolean ok;
char answer;
System.out.println ("Numerele de 3 cifre egale cu suma
cuburilor cifrelor sunt:");

for (n = 100; n < 999; n++){


n1 = n;
c = n1 % 10;
n1 = n1 / 10;
b = n1 % 10;
a = n1 / 10;
ok = false;
if (n == (a*a*a + b*b*b + c*c*c))
ok = true;
if (ok == true)
System.out.print(" "+ n);
}

System.out.println(" ");
}
}

9.12 Conversia unui număr fracţionar din baza p în baza q

import java.io.*;

/*

212
Fie p si q două baze de numeratie şi m numărul de cifre pentru a =
(am, am-1, …, a0) (pur fracţionar) scris în baza p.
 Să se citească şi să se valideze m, p, q şi a;
 Să se realizeze conversia lui a din baza p în baza q;
 Să se afişeze lista cifrelor numărului obţinut.
*/
class doisprezece
{
static char []S = {'0', '1', '2', '3', '4', '5', '6', '7', '8',
'9', 'A', 'B', 'C', 'D', 'E', 'F'};

public static String vi (int k){


char rez = 0;
switch (k) {
case 0: rez = '0'; break;
case 1: rez = '1'; break;
case 2: rez = '2'; break;
case 3: rez = '3'; break;
case 4: rez = '4'; break;
case 5: rez = '5'; break;
case 6: rez = '6'; break;
case 7: rez = '7'; break;
case 8: rez = '8'; break;
case 9: rez = '9'; break;
case 10: rez = 'A'; break;
case 11: rez = 'B'; break;
case 12: rez = 'C'; break;
case 13: rez = 'D'; break;
case 14: rez = 'E'; break;
case 15: rez = 'F'; break;
default: System.out.println("Not a valid number"); rez = '.';
break;
}

return rez + "";

public static int v(char k){

213
int rez = 0;
switch (k) {
case '0': rez = 0; break;
case '1': rez = 1; break;
case '2': rez = 2; break;
case '3': rez = 3; break;
case '4': rez = 4; break;
case '5': rez = 5; break;
case '6': rez = 6; break;
case '7': rez = 7; break;
case '8': rez = 8; break;
case '9': rez = 9; break;
case 'A': rez = 10; break;
case 'B': rez = 11; break;
case 'C': rez = 12; break;
case 'D': rez = 13; break;
case 'E': rez = 14; break;
case 'F': rez = 15; break;
default: System.out.println("Not a character"); rez = -1;
break;
}

return rez;

public static int baza3(int p, char[] a, int m){


int Pr, code, n, i;
n = 0;
//trece din baza p in baza 10 pt partea intreaga
Pr = 1;
for (i = 0; i < m; i++){
n = n + v(a[i]) * Pr;
Pr = Pr * p;
}
return n;

}
public static void baza1(int n, int q){
char s[];

214
int k;
int i = -1;
s = new char [16];
i = -1;
//trece din baza 10 in baza q pt partea intreaga
while (n != 0){
i = i + 1;
s[i] = (char)(n % q);
n = n / q;
}
for (k = i; k >= 0; k--)
System.out.print(vi(s[k]) + "");
System.out.println(" ");
}

public static void main (String argv[])


{

char a[], numar [];


numar = new char [16];
a = new char [16];
boolean valid;
int p, q, m, i, n, k, x;
String t, baza1 = "", baza2 = "", s1= "", s2 = "";

while (true){

InputStreamReader stdin = new


InputStreamReader(System.in);
BufferedReader console = new BufferedReader(stdin);
try
{

//mai intai citesc numarul de cifre m


System.out.print("m = ");
s1 = console.readLine();
m = Integer.parseInt(s1);
if (m < 0 || m > 16)
{
System.out.println("Numarul de cifre este invalid");

215
System.exit(1);

}
//apoi citesc baza p
System.out.print("p = ");
baza1 = console.readLine();
p = Integer.parseInt(baza1);
if (p < 2 || p > 16)
{
System.out.println("Baza de numeratie " + baza1
+ " este invalida");
System.exit(1);

}
//apoi citesc baza q
System.out.print("q = ");
baza2 = console.readLine();
q = Integer.parseInt(baza2);
if (q < 2 || q > 16)
{
System.out.println("Baza de numeratie " + baza2
+ " este invalida");
System.exit(1);

}
//apoi citesc numarul a
for (i = m-1; i >= 0; i--){
System.out.print("a[" + i + "] = ");
// citesc numarul a[i], a i-a cifra a numarului a
s2 = console.readLine();
a[i] = s2.charAt(0);
}

for (i = m-1; i >= 0; i--){


valid = false;
//verific corectitudinea numarului a in baza p
for (int j = 0; j < 16; j++)
{
if (a[i] == S[j]){
valid = true;

216
break;
}

}
if (valid == false ){
System.out.println("Numar invalid");
System.exit(1);
}
}

n = baza3(p,a,m);
baza1(n,q);
System.out.println(" ");

}
catch(IOException ioex)
{
System.out.println("Eroare la intrare");
System.exit(1);
}
catch(NumberFormatException nfex)
{
System.out.println("\"" + nfex.getMessage() + "\"
nu este un numar");
System.exit(1);
}
}
}
}

9.13 Controlul bitului de paritate

217
import java.io.*;

/*
Fie n numărul de cifre binare pentru a = (a1, a2, …, an) care urmează să
fie trimis cu o paritate dată, p.
 Să se citească şi să se valideze n, p şi a;
 Să se stabilească dacă informaţia a fost transmisă corect;
*/
class treisprezece
{
public static void main (String argv[])
{

int n, i, p, nr;
boolean ok;
char a[];
a = new char [16];
String t, s1 = "", s2 = "";
System.out.println("Calculul paritatii unui şir de cifre:");

while (true){

InputStreamReader stdin = new


InputStreamReader(System.in);
BufferedReader console = new BufferedReader(stdin);
try
{
//mai intai citesc numarul de cifre n
System.out.print("n = ");
s1 = console.readLine();
n = Integer.parseInt(s1);
if ((n < 1) || (n > 16)){
System.out.println("Numar incorect de cifre!");
System.exit(0);
}

//apoi citesc paritatea p


System.out.print("p = ");
s1 = console.readLine();

218
p = Integer.parseInt(s1);
if ((p != 1) && (p != 0)){
System.out.println("Cifra incorecta");
System.exit(0);
}
//apoi citesc numarul a
for (i = n-1; i >= 0; i--){
System.out.print("a[" + i + "] = ");
// citesc numarul a[i], a i-a cifra a numarului a
s2 = console.readLine();
a[i] = s2.charAt(0);
if ((a[i] != '0') && (a[i] != '1')){
System.out.println("Cifra incorecta");
System.exit(0);
}
}
nr = 0;
for (i = 1; i < n; i++){
if (a[i] == '1')
nr ++;
}
if ((p+nr) % 2 == 0)
System.out.println("corect!");
else
System.out.println("incorect!");
}
catch(IOException ioex)
{
System.out.println("Eroare la intrare");
System.exit(1);
}
catch(NumberFormatException nfex)
{
System.out.println("\"" + nfex.getMessage() + "\"
nu este un numar");
System.exit(1);
}
}
}
}

219
9.14 Codul lui Hamming pentru emisie mesaj

import java.io.*;

/*
Fie o transmisie care utilizează CH cu paritate impară pentru un mesaj
binar pe m biţi.
 Să se citească şi să se valideze m şi mesajul de transmis;
 Să se calculeze cei k biţi de control;
 Să se afişeze mesajul transmis pe n = m + k biţi.
*/

class paisprezece
{
public static void main (String argv[])
{

int i, m, n, k, p, j, poz, l;
boolean ok;
char a[], b[];
a = new char [50];
b = new char [50];
String t, s1 = "", s2 = "";
System.out.println("Codul lui Hamming pentru emisie mesaj");

while (true){

InputStreamReader stdin = new


InputStreamReader(System.in);
BufferedReader console = new BufferedReader(stdin);
try
{
//mai intai citesc numarul de cifre n
System.out.print("n = ");
s1 = console.readLine();
n = Integer.parseInt(s1);
if ((n < 1) || (n > 50)){
System.out.println("Numar n incorect!");
System.exit(0);
}
220
//apoi citesc vectorul binar b
for (i = n-1; i >= 0; i--){
System.out.print("b[" + i + "] = ");
// citesc numarul b[i], a i-a cifra a vectorului b
s2 = console.readLine();
b[i] = s2.charAt(0);
if ((b[i] != '0') && (b[i] != '1')){
System.out.println("Cifra incorecta");
System.exit(0);
}
}
k = 0;
p = 1;
while (p < n+1){
k = k + 1;
p = p * 2;
}
m = n - k;
for (j = 0; j < k; j++)
a[j] = 0;
for (i = 0; i < n; i++){
p = i;
l = 1;
while (p > 0){
a[l] += b[i]*(p % 2);
p = p / 2;
l = l + 1;
}
}
for (i = 0; i < k; i++)
if (a[i] % 2 == 0)
a[i] = 1;
else
a[i] = 0;
s = 0;
p = 1;
for (i = 0; i < k; i ++){
s = s + p * a[i];
p = p * 2;
}

221
if (s == 0)
System.out.println("Transm. Fara eroare");
else {
System.out.println("Eroare la bitul " + s);
if (b[s] == 1)
b[s] = 0;
else
b[s] = 1;
System.out.println("");

}
poz = p / 2;
m = n;
for (i = k; i>0; i--){
for (j = poz; j < m-1; j++)
b[j] = b[j+1];
m = m-1;
poz = poz / 2;
}
for (i = m; i > 0; i--)
System.out.println(b[i]);
}
catch(IOException ioex)
{
System.out.println("Eroare la intrare");
System.exit(1);
}
catch(NumberFormatException nfex)
{
System.out.println("\"" + nfex.getMessage() +
"\" nu este un numar");
System.exit(1);
}
}
}
}

222
9.15 Codul lui Hamming pentru recepţie mesaj

import java.io.*;

/*
Fie o transmisie care utilizează CH cu paritate impară prin care s-a
receptionat un mesaj binar pe n biti.
 Să se citească şi să se valideze n şi mesajul receptionat;
 Să se verifice cei k biti de control de paritate;
 Să se afişeze mesajul iniţial pe m = n - k biţi, după corectarea
eventualelor erori.
*/

class cincisprezece
{
public static void main (String argv[])
{

int i, m, n, k, p, j, poz, s, l;
boolean ok;
char a[], b[];
a = new char [50];
b = new char [50];
String t, s1 = "", s2 = "";
System.out.println("Codul lui Hamming pentru receptie mesaj");

while (true){

InputStreamReader stdin = new


InputStreamReader(System.in);
BufferedReader console = new BufferedReader(stdin);
try
{
//mai intai citesc numarul de cifre m
System.out.print("m = ");
s1 = console.readLine();
m = Integer.parseInt(s1);
if ((m < 1) || (m > 50)){
System.out.println("Numar m incorect!");
223
System.exit(0);
}

//apoi citesc vectorul binar b


for (i = m-1; i >= 0; i--){
System.out.print("b[" + i + "] = ");
// citesc numarul b[i], a i-a cifra a vectorului b
s2 = console.readLine();
b[i] = s2.charAt(0);
if ((b[i] != '0') && (b[i] != '1')){
System.out.println("Cifra incorecta");
System.exit(0);
}
}
k = 0;
p = 1;
while (p < m + k + 1){
k = k + 1;
p = p * 2;
}
n = m;
poz = 1;
for (i = 1; i < k; i++){
for (j = n-1; j >= poz; j--)
a[j+1] = a[j];
n = n+1;
a[poz] = 0;
poz = poz*2;
}
for (j = 0; j < k; j ++)
b[j] = 0;
for (i = 0; i < n; i++){
p = i;
l = 1;
while (p > 0){
b[l] += a[i]*(p % 2);
p = p / 2;
l = l+1;
}
}

224
poz = 1;
for (i = 0; i < k; i++){
if ((b[i] %2) == 0)
a[poz] = 1;
poz = poz * 2;
}
for (i = n-1; i >= 0; i--)
System.out.print(a[i]);
System.out.println("");
System.out.println("End.");

}
catch(IOException ioex)
{
System.out.println("Eroare la intrare");
System.exit(1);
}
catch(NumberFormatException nfex)
{
System.out.println("\"" + nfex.getMessage() + "\"
nu este un numar");
System.exit(1);
}
}
}
}

225
9.16 Fişiere în Java

import java.io.*;

/*
Implementare fisier cu studentii din facultate împărtiti pe grupe: citire,
afisare, contorizare.
*/
class saisprezece
{
public static void main (String argv[])
{
String numefis;
String numeg;
FileOutputStream fout;
FileInputStream fin;
int n, i;
String t, s1 = "", s2 = "";
InputStreamReader stdin = new InputStreamReader(System.in);
BufferedReader console = new BufferedReader(stdin);

try
{
System.out.print("Dati numele fisierului: ");
numefis = console.readLine();
// Deschidere output stream
fout = new FileOutputStream (numefis);

//mai intai citesc numarul de grupe n


System.out.print("n = ");
s1 = console.readLine();
n = Integer.parseInt(s1);
for (i = 1; i <= n; i++){
System.out.println("grupa" + i + ":");
numeg = console.readLine();
//Scriere a unei linii de text
new PrintStream(fout).println (numeg);
}
//Inchiderea fisierului de intrare
226
fout.close();
System.out.print("Grupele citite din fisier sunt: ");
// Deschidere input stream
fin = new FileInputStream (numefis);

// Citesc fiecare linie din fisier


for (i = 1; i <= n; i++){
System.out.println(new DataInputStream(fin).readLine());
}

fin.close();
}
// Pentru tratarea conditiilor de eroare
catch (IOException e)
{
System.err.println ("Unable to write to file");
System.exit(-1);
}
catch(NumberFormatException nfex)
{
System.out.println("\"" + nfex.getMessage() + "\" nu este un
numar");
System.exit(1);
}
}
}

227
9.17 Eliminare spaţii excedentare şir de caractere

import java.io.*;

/*
Modelare text citit de la tastatură prin eliminarea spatiilor excedentare.
*/
class saptesprezece
{
public static int i, j;
public static char a[], b[];
public static void sf(){

i = 0;
while(i < j){
System.out.print(b[i]);
i = i+1;
}
System.out.print(" ");
}

public static void spinit(){


i = i+1;
if (a[i] == ' ')
spinit();
else if (a[i] == '%')
sf();
else {
j = j+1;
b[j] = a[i];
cuvant();
}
}

public static void spatiu(){


i = i+1;
if (a[i] == ' ')
spatiu();
else if (a[i] == '%')
228
sf();
else {
j = j+1;
b[j] = ' ';
j = j+1;
b[j] = a[i];
cuvant();
}
}

public static void cuvant(){


i = i+1;
if (a[i] == ' ')
spatiu();
else if (a[i] == '%')
sf();
else {
j = j+1;
b[j] = a[i];
cuvant();
}
}

public static void main (String argv[])


{
i = 0;
j = -1;
a = new char[200];
b = new char [200];
String t, s1 = "", s2 = "";

InputStreamReader stdin = new


InputStreamReader(System.in);
BufferedReader console = new BufferedReader(stdin);

System.out.print("Introduceti textul litera cu litera! ");


System.out.println("Terminati cu caracterul %! ");
while (true){
try
{

229
//se citeste caracter cu caracte textul
s1 = console.readLine();
a[i] = s1.charAt(0);
i = i+1;
if (a[i-1] =='%'){
//caracter de final
a[i-1] = '}';
a[i] = '%';
i = -1;
System.out.println("Textul corectat este: ");
spinit();
System.out.println(" ");
System.out.println(" ");
break;
}
}
// Pentru tratarea conditiilor de eroare
catch (IOException e)
{
System.err.println ("Unable to write to file");
System.exit(-1);
}
}
}
}

230
9.18 Conversie din reprezentare externă în VMSP

import java.io.*;

/*
Fie numărul zecimal N o reprezentare externă a informatiei unui
sistem de calcul.
· Să se citească repetat si să se valideze N;
· Să se stabilească reprezentarea internă în VMSP a lui N;
· Să se afiseze în hexazecimal această valoare.
*/

class optsprezece
{

public static String vi (int k){


char rez = 0;
switch (k) {
case 0: rez = '0'; break;
case 1: rez = '1'; break;
case 2: rez = '2'; break;
case 3: rez = '3'; break;
case 4: rez = '4'; break;
case 5: rez = '5'; break;
case 6: rez = '6'; break;
case 7: rez = '7'; break;
case 8: rez = '8'; break;
case 9: rez = '9'; break;
case 10: rez = 'A'; break;
case 11: rez = 'B'; break;
case 12: rez = 'C'; break;
case 13: rez = 'D'; break;
case 14: rez = 'E'; break;
case 15: rez = 'F'; break;
default: System.out.println("Not a valid number"); rez = '.';
break;
}

231
return rez + "";
}
public static int v(char k){
int rez = 0;
switch (k) {
case '0': rez = 0; break;
case '1': rez = 1; break;
case '2': rez = 2; break;
case '3': rez = 3; break;
case '4': rez = 4; break;
case '5': rez = 5; break;
case '6': rez = 6; break;
case '7': rez = 7; break;
case '8': rez = 8; break;
case '9': rez = 9; break;
case 'A': rez = 10; break;
case 'B': rez = 11; break;
case 'C': rez = 12; break;
case 'D': rez = 13; break;
case 'E': rez = 14; break;
case 'F': rez = 15; break;
default: System.out.println("Not a character"); rez = -1;
break;
}

return rez;

public static int sgn(float x){


int sign;
if (x < 0)
sign = -1;
else
sign = 1;
return sign;
}

public static void main (String argv[])

232
{

int semn, ni, i, j, er, ed, l, x;


float n, nr;
int ai[], ar[], b[], c[];
ai = new int [100];
ar = new int [100];
b = new int [100];
c = new int [100];
String baza, s1= "", s2 = "", w1;

while (true){

InputStreamReader stdin = new


InputStreamReader(System.in);
BufferedReader console = new BufferedReader(stdin);
try
{
System.out.print("Introduceti nr. real n= ");
s1 = console.readLine();
n = Float.parseFloat(s1);
ni = (int)(Math.abs(n));
nr = Math.abs(n) - ni;
semn = sgn(n);
i = -1;
while (ni > 0){
i = i+1;
ai[i] = (int)(ni % 2);
ni = ni / 2;
}
j = 0;
while (nr > 0){
j = j+1;
ar[j] = (int)(nr*2);
nr = nr*2 - ar[j];
}
er = i + 1;
ed = er + 128;
if (semn > 0)
b[0] = 0;

233
else
b[0] = 1;
for (i = 1; i < 31; i++)
b[i] = 0;
l = 8;
while (ed > 0){
b[l] = (int)(ed % 2);
l = l-1;
ed = ed / 2;
}
for (i = 1; i < er; i++)
b[8+i] = ai[er-i];
for (i = 1; i < j; i++)
b[8+er+i] = ar[i];
System.out.println("Reprezentarea interna in VMSP a lui N este:");
for (i = 0; i < 31; i++)
System.out.print(b[i]+"");

System.out.println(" ");
System.out.println("Reprezentarea in hexazecimal este:");

for (i = 0; i < 7; i++){


c[i] = 8*b[4*i] + 4*b[4*i+1] +
2*b[4*i+2] + b[4*i+3];
System.out.print(vi(c[i]));
}
System.out.println(" ");
}
catch(IOException ioex)
{
System.out.println("Eroare la intrare");
System.exit(1);
}
catch(NumberFormatException nfex)
{
System.out.println("\"" + nfex.getMessage() + "\" nu este un numar");
System.exit(1);
}
}
}

234
}

9.19 Conversie din VMSP în reprezentare externă

import java.io.*;

/*
Fie numărul N în sistem octal o reprezentare internă în VMSP.
 Să se citească repetat şi să se valideze N;
 Să se stabilească reprezentarea externă a lui N;
 Să se afiseze în zecimal această valoare.
*/
class nouasprezece
{
public static void main (String argv[])
{

int m;
boolean valid = true;
int p, s, c, i, k, er;
float n, x, sr, pr;
int a[], b[];
a = new int [100];
b = new int [100];
String baza, s1= "", s2 = "", w1;

while (true){

InputStreamReader stdin = new


InputStreamReader(System.in);
BufferedReader console = new BufferedReader(stdin);
try
{
System.out.println("Introduceti numarul de cifre
intre 1 şi 10: ");
s1 = console.readLine();
m = Integer.parseInt(s1);
235
if ((m < 1) || (m > 10)){
System.out.println("Numarul de cifre este
invalid");
System.exit(1);

}
System.out.print("Introduceti a[0] un intreg intre 0
şi 3 ");
s1 = console.readLine();
a[0] = Integer.parseInt(s1);
if ((a[0] < 0) || (a[0] > 3)){
System.out.println("Numarul de cifre este invalid");
System.exit(1);

}
//apoi citesc numarul a
for (i = 1; i < m; i++){
System.out.print("a[" + i + "] = ");
// citesc numarul a[i], a i-a cifra a numarului a
s2 = console.readLine();
a[i] = s2.charAt(0);
}
valid = true;
for (i = 1; i < m; i++){
if ((a[i] < '0') || (a[i] > '7')){
valid = false;
break;
}
}
if (valid == false ){
System.out.println("Numar invalid");
System.exit(1);
}
for (i = 0; i < m; i++)
System.out.print("" + a[i]);
System.out.println("");
b[0] = a[0] / 2;
b[1] = a[0] % 2;
for (i = 1; i < m; i++){
c = a[i];

236
b[3*i+1] = c % 2;
c = c / 2;
b[3*i] = c / 2;
b[3*i-1] = c / 2;
}
k = 2+m*3;
for (i = k; i < 31; i++)
b[i] = 0;
for (i = 0; i < 31; i++)
System.out.print("" + b[i]);
System.out.println("");
if (b[0] == 1)
System.out.print("-");
else
System.out.print("+");
s = 0;
p = 1;
for (i = 8; i >= 1; i--){
s = s + b[i]*p;
p = p*2;
}
er = s-128;
sr = 0;
pr = 1/2;
for (i = 9; i < 31; i++){
sr = sr+b[i]*pr;
pr = pr/2;
}
System.out.print(sr+ "*" + " 2 la puterea " + er);
System.out.println(" ");
}
catch(IOException ioex)
{
System.out.println("Eroare la intrare");
System.exit(1);
}
catch(NumberFormatException nfex)
{
System.out.println("\"" + nfex.getMessage() + "\"
nu este un numar");

237
System.exit(1);
}
}
}
}

9.20 Linie de lungime maximă într-un fişier text

import java.io.*;

// Determinarea si afisarea celei mai lungi linii dintr-un fisier text.

class ceaMaiLungaLinie
{
public static void main (String argv[])
{
String numefis;
String line = "";
FileInputStream fin;
int maxLength = 0;
String maxLine = "";

InputStreamReader stdin = new


InputStreamReader(System.in);
BufferedReader console = new BufferedReader(stdin);

try
{
System.out.println("Dati numele fisierului: ");
numefis = console.readLine();

// Deschidere input stream


fin = new FileInputStream (numefis);

// Citesc fiecare linie din fisier


while ((line = new DataInputStream(fin).readLine()) != null)
{
if(line.length() > maxLength){
maxLength = line.length();
maxLine = line;
238
}
}
fin.close();

if(maxLength == 0)
System.out.println("Fisierul de intrare este gol. ");
else{
System.out.println("Cea mai lunga linie este");
System.out.println(maxLine);
System.out.println("si are");
System.out.println(maxLength + " caractere.");
}
}
catch(Exception e)
{
System.out.println("Eroare citire fisier");
System.exit(1);
}
}
}

239
BIBLIOGRAFIE SELECTIVĂ

Aho 93 A. Aho, J. Ullman. Concepts fondamentaux de


l’informatique, Dunod, Paris, 1993.
Boia 94 F. M. Boian. Sisteme de operare interactive, Libris,
Cluj-Napoca, 1994.
Boia 96 F. M. Boian. De la aritmetică la calculatoare, Presa
Universitară Clujeană, 1996.
Bour 93 P. Boursier, P.-A. Taufour. La technologie multimédia,
Collection Informatique, Hermès, Paris, 1993.
Culm 72 G. Cullman. Coduri detectoare şi corectoare de erori,
Ed. Tehnică, Bucureşti, 1972.
Cout 90 J. Coutaz. Interfaces homme-machine: conception et
réalisation, Dunod, 1990.
Cris 92 V. Cristea şi colab. Reţele de calculatoare, Teora, 1992.
Elli 90 M. Ellis, B. Stroustrup. The annotated C++ reference
manual, Addison Wesley, 1990.
Ferb 91 J. Ferber. Conception et programmation par objets,
Hermès, Paris, 1991.
Knut 83 D. E. Knuth. Tratat de programarea calculatoarelor,
Ed. Tehnică, Bucureşti, 1983.
Riff 93 J. M. Rifflet. La programmation sous UNIX, Ediscience
international, 1993.
Ţănd 94 N. Ţăndăreanu. Introducere în programarea logică.
Limbajul Prolog. Intarf, 1994.
Vădu 85 I. Văduva, V. Baltac şi colab. Medii de programare.
Viitorul industriei de programe, Ed. Academiei,
Bucureşti, 1985.
Vlad 93 FL. V. Pilat. Calculatoare personale. WINDOWS 3.1,
Teora, 1993.
Zane 93 P. Zanella, Y. Ligier. Architecture et technologie des
ordinateurs, Dunod, Paris, 1993.

240
[Null 03] L. Null, J. Lobur, The Essentials of Computer
Organization and Architecture, Jones and Bartlett
Publishers, 2003.

241

S-ar putea să vă placă și