Differences

This shows you the differences between two versions of the page.

Link to this comparison view

programare:laboratoare:lab06 [2017/11/09 00:45]
darius.neatu [Exerciții]
programare:laboratoare:lab06 [2021/10/24 14:14] (current)
andrei.traistaru99 [Exerciţii de Laborator]
Line 1: Line 1:
- +===== Matrice. Operaţii cu matrice: adunare, înmulţire. Reprezentarea în memorie. ​=====
-===== Optimizarea programelor folosind operaţii pe biţi  ​=====+
  
 **Responsabili:​** **Responsabili:​**
-  * [[neatudarius@gmail.com|Darius Neațu (2017)]] +  * [[neatudarius@gmail.com|Darius Neațu (CA 2019-2020)]] 
-  * [[rares96cheseli@gmail.com|Rareș Cheșeli ​(2017)]] +  * [[ion_dorinel.filip@cti.pub.ro|Dorinel Filip (CA 2019-2020)]] 
 +  * [[andrei.parvu@cti.pub.ro|Andrei Pârvu]] 
  
-==== Obiective ==== +[[https://​docs.google.com/​document/​d/​16GNacxqmnRjaBx7w8tt9rRprbpiOjx8njzIrv4Q0mI0/​edit?​usp=sharing|Probleme]]
  
-În urma parcurgerii acestui laborator, studentul va fi capabil: +[[https://we.tl/t-HTa9YV1Wvg|Teste]] 
-  * să înțeleagă conceptele legate de operații pe biți +==== Obiective =====
-  * să utilizeze operații pe biți pentru optimizare (când este cazul) +
-  * să înteleagă mai multe despre organizarea datelor în memorie +
-  * să gestioneze mai bine memoria folosită într-un anumit program C +
-  * să implementeze o structură de date in C+
  
-<note warning> +În urma parcurgerii acestui laborator studentul va fi capabil: 
-    Laboratorul curent introduce mai multe noțiuni. Pe multe dintre acestea le veți mai întâlni și la alte cursuri din următorii aniprecum: IOCLACN/CN2, AA/PA, PC, PM, SO. +  să declare matrice si orice fel de tablou multidimensional;​  
-    * Secțiunile *Studiu ​de caz ** și ** Probleme ​de interviu ​** nu sunt obligatorii,​ dar recomandăm parcurgerea întregului material ​pentru ​o viziune ​de ansamblu mai bună. +  * sa initializeze aceste structuriatat din declaratiecat si prin instructiuni iterative; ​ 
-</​note>​+  sa cunoasca regulile ​de reprezentare ale tablourilor in memorie si sa inteleaga modul in care compilatorul interpreteaza operatorii de indexare;  
 +  ​sa cunoasca scheme comune ​de utilizare a acestor structuri;  
 +  ​sa foloseasca practici recunoscute si recomandate ​pentru ​scrierea ​de cod sursa care implica lucrul cu matrice; 
 +  * sa recunoasca si sa evite erorile comune de programare legate de aceste structuri
  
-==== Motivație ==== 
-În cadrul acestui articol vă vom prezenta câteva metode prin care programele se pot optimiza dacă utilizăm eficient operaţiile pe biţi. Un lucru foarte important de reținut este că nu întotdeauna putem folosi aceste operații pentru optimizare, iar laboratorul are ca scop ilustrarea câtorva cazuri particulare,​ pe care le puteți întâlni și pe viitor. 
  
-Veți învăța în anul 2 la Analiza Algoritmilor despre complexitatea unui algoritm. Vom considera momentan că un algoritm este mai rapid decât altul dacă are mai puțini pași (exemplu un for cu n = 100 de pași este mai rapid decât un for cu 1000 de pași). ​ 
  
-În exemplul anterior performanța se referea la timp (dacă executăm mai puține instrucțiuni într-un program, ne așteptăm să se termine mai repede). Acest aspect va fi abordat pe larg la materiile AA și PA. +==== Noţiuni teoretice ====
  
-În acest laborator vom vorbi despre altă metrică de măsurare a performanței unui program, mai exact despre ** memoria folosită ** de un program. +=== Matrice ===
-De ce este important și acest aspect? Dacă din punct de vedere al timpului de execuție, sunt situații în care putem aștepta mai mult timp pentru a se termina programul, din punctul de vedere al memoriei folosite avem o limitare exactă. Un exemplu simplu este calculatorul nostru, care are 4GB/​8GB/​16GB. Dacă mașina noastră are X GB RAM, dintre care o parte importantă o ocupă sistemul de operare, asta înseamnă că într-un anumit program nu putem folosi o cantitate nelimitată de RAM (mai multe detalii despre **swap** veți învăța în cursurile următoare - CN2, SO). Momentan presupunem că programul nostru nu poate rula pe o mașină cu X GB, dacă are nevoie de mai mult de X GB. +
-  +
-Dacă ajungem într-o astfel de situație în mod evident trebuie să schimbăm ceva, însă de multe ori putem păstra algoritmul și să facem câteva modificări în implementare,​ care exploatează anumite abilități ale limbajului C (ex. operații pe biți).+
  
-==== Dimensiunea tipurilor implicite ​în CCalculul memoriei unui program ====+Matricea este o colecţie omogenă şi bidimensională de elemente. Acestea pot fi accesate prin intermediul a doi indici, numerotaţi,​ ca şi în cazul vectorilor, începand de la 0Declaraţia unei matrice este de forma:
  
-În [[https://​ocw.cs.pub.ro/​courses/​programare/​laboratoare/​lab02|laboratorul 2]] au prezentate tipurile de date implicite din C și dimensiunea acestora.+<code bash> 
 +<​tip_elemente>​ <​nume_matrice>​[<​dim_1>​][<​dim_2>​];​ 
 +</code>
  
-Pentru a afla ** dimensiunea în bytes ** a unei variabile se poate folosi operatorul **sizeof**. +De exemplu, avem: 
- +<code c
-<spoiler Exemplu+int mat[5][10];​ 
-Fie codul din următorul cod.+</​code>​
 <code c> <code c>
 +#define MAX_ELEM 100
 +float a[MAX_ELEM][MAX_ELEM];​
 +</​code>​
  
-#include <stdio.h>+Numărul de elemente ale unei matrice va fi ''​dim_1*dim_2'',​ şi semnificaţia fiecărei dimensiuni este o chestiune ce ţine de logica programului. În matematică,​ prima dimensiune poate să însemne linia şi a doua coloana pentru fiecare element, însa acest lucru nu este obligatoriu. Este necesar totuşi, pentru funcţionarea corectă a programului,​ să se respecte semnificaţiile alese pe întreg parcursul codului sursă.
  
-int main() { +=== Tablouri multidimensionale ​===
-    // afiseaza dimensiunea tipurilor si a unor variabile de un anumit tip +
-    char xc; +
-    printf("​sizeof(unsigned char) %ld B\n", sizeof(unsigned char)); +
-    printf("​sizeof(char) ​%ld B\n", sizeof(char));​ +
-    printf("​sizeof(xc) ​%ld B\n", sizeof(xc));​ +
- +
-    short int xs; +
-    printf("​sizeof(unsigned short int) %ld B\n", sizeof(unsigned short int)); +
-    printf("​sizeof(short int) %ld B\n", sizeof(short int)); +
-    printf("​sizeof(xs) ​%ld B\n", sizeof(xs));​ +
- +
-    int xi; +
-    printf("​sizeof(unsigned int) = %ld B\n", sizeof(unsigned int)); +
-    printf("​sizeof(int) = %ld B\n", sizeof(int));​ +
-    printf("​sizeof(xi) = %ld B\n", sizeof(xi));​ +
- +
-    // afiseaza dimensiunea unor tablouri cu dimensiune cunoscuta +
-    char vc[100]; +
-    short int vs[100]; +
-    int vi[100]; +
-    printf("​sizeof(vc) = %ld B\n", sizeof(vc));​ +
-    printf("​sizeof(vs) = %ld B\n", sizeof(vs));​ +
-    printf("​sizeof(vi) = %ld B\n", sizeof(vi));​ +
- +
-    return 0; +
-}+
  
 +Vectorii şi matricele se pot extrapola la noţiunea generală de tablou cu mai multe dimensiuni, care se declară în modul următor:
  
 +<code bash>
 +<​tip_elemente>​ <​nume_tablou>​[<​dim_1>​][<​dim_2>​]...[<​dim_n>​];​
 </​code>​ </​code>​
  
-În urma executării acestui program pe o arhitectură de 32 biți vom vedea următorul rezultat. +De exemplu: 
- +<​code ​c
-<​code>​ +int cube[3][3][3];​
- +
-sizeof(unsigned char) = 1 B +
-sizeof(char) = 1 B +
-sizeof(xc) = 1 B +
- +
-sizeof(unsigned short int) = 2 B +
-sizeof(short int) = 2 B +
-sizeof(xs) = 2 B +
- +
-sizeof(unsigned int) = 4 B +
-sizeof(int) = 4 B +
-sizeof(xi) = 4 B +
- +
-sizeof(vc) = 100 B +
-sizeof(vs) = 200 B +
-sizeof(vi) = 400 B +
 </​code>​ </​code>​
-</​spoiler>​ 
  
-<​note>​ +Deşi, în cazul a mai mult de 3 dimensiuni, tablourile pot să nu mai aibă sens concret sau fizic, acestea pot fi deosebit de utile în multe situaţii. În acest laborator ne vom rezuma totuşi la tablouri bidimensionale.
-Putem afla dimensiunea unui tip de date / variabila de un anumit tip la ** compile time ** folosind operatorul sizeof care returnează dimensiunea ​în bytes a parametrului dat.+
  
-**sizeof** poate fi folosit și pentru măsurarea dimesiunii unui vector / matrice alocat(a) static.+=== Adunarea si înmulţirea matricelor ===
  
-Memoria totală folosită de un program poate fi calculată ca suma tuturor dimensiunilor ocupate de variabilele din program.+== Suma matricelor ==
  
-De obiceine interesează să știm ** ordinul de mărime ** al spațiului de memorie alocatastfelde cele mai multe oriputem contoriza doar tablourile.+Fie $A \in {\mathbb R}^{m \times n}$$B \in {\mathbb R}^{\times n}$, atunci $(A+B) \in {\mathbb R}^{m \times n}$, unde: $(A+B)_{i,j} =  A_{i,j} + B_{i,j}$
  
-Un caz special îl poate reprezenta recursivitatea! Punerea parametrilor pe stivă de un număr foarte mare de ori, este echivalent cu declararea unui tablou de valori pe stivăAceste variabile nu pot fi neglijate în calculul memoriei!+{{:​programare:​laboratoare:​sum.png|}}
  
-Vom descoperi mai multe în următoare laboratoare. ​:+Exemplu:
-</​note>​+
  
-==== Operatori pe biți în C ====+$$ 
 +  \Large 
 +  \begin{bmatrix} 
 +     1 & 3 \\  
 +     0 & 4 \\ 
 +     5 & 8 
 +  \end{bmatrix} 
 +
 +  \begin{bmatrix}  
 +    2 & 5 \\  
 +    1 & 2 \\  
 +    6 & 1 
 +  \end{bmatrix} 
 += 
 +  \begin{bmatrix} 
 +    3 & 8 \\  
 +    1 & 6 \\  
 +    11 & 9 
 +  \end{bmatrix} 
 +$$
  
-Operatorii limbajului C pot fi unari, binari sau ternari, fiecare având o precedenţă şi o asociativitate bine definite (vezi [[https://​ocw.cs.pub.ro/​courses/​programare/​laboratoare/​lab02 | lab02]]).+== Înmulţirea matricelor ==
  
-În tabelul următor reamintim operatorii limbajului C care sunt folosiți la nivel de bit.+Fie $A \in {\mathbb R}^{m \times n}$, $B \in {\mathbb R}^{n \times p}$, atunci $(AB) \in {\mathbb R}^{m \times p}$, unde elementele $A.B$ sunt date de formula: 
 +$(AB)_{i,j} = \sum_{r=1}^n A_{i,​r}B_{r,​j}$
  
-^ Operator ​ ^  Descriere ​ ^  Asociativitate ​ ^ 
-|  **%%~%%** ​ | Complement faţă de 1 pe biţi |  dreapta-stânga ​ | 
-|  **%%<<​%% si %%>>​%%** ​ | Deplasare stânga/​dreapta a biţilor |  stânga-dreapta ​ | 
-|  **&​** ​ | ŞI pe biţi |  stânga-dreapta ​ | 
-|  **^**  | SAU-EXCLUSIV pe biţi |  stânga-dreapta ​ | 
-|  **|**  | SAU pe biţi |  stânga-dreapta ​ | 
-|  **&=** și **|=** ​ | Atribuire cu ŞI/SAU |  dreapta-stânga ​ | 
-|  **^=** ​ | Atribuire cu SAU-EXCLUSIV |  dreapta-stânga ​ | 
-|  **%%<<​=%%** şi **%%>>​=%%** ​ | Atribuire cu deplasare de biţi |  dreapta-stânga ​ | 
  
-<note warning>​ +{{:​programare:​laboratoare:​mul.png|}} Exemplul din stânga prezintă cum se calculează valorile (1,2) si (3,3) ale '''​AB'''​ daca '''​A'''​ este o matrice 3×2, si '''​B'''​ o matrice 2×3. Pentru calculul unui element din matrice se consideră o linie respectiv o coloană din fiecare matrice conform săgeţilor. Elementele din acestea sunt înmulţite câte 2 conform înmulţirii pe vectori, apoi suma produselor constituie elementul din matricea finală
-Trebuie avută în vedere precedenţa operatorilor pentru obţinerea rezultatelor dorite!+
  
-Dacă nu sunteți sigur de precendența unui operatorfolosiți o pereche de paranteze rotunde în plus în expresia voastră! Nu exagerați cu parantezelecodul poate deveni ilizibil. +$$ 
-</​note>​+  (\mathbf{AB})_{1,​2} = \sum_{r=1}^2 a_{1,​r}b_{r,​2} = a_{1,​1}b_{1,​2}+a_{1,​2}b_{2,​2} \\  
 +  (\mathbf{AB})_{3,​3} = \sum_{r=1}^2 a_{3,​r}b_{r,​3} = a_{3,​1}b_{1,​3}+a_{3,2}b_{2,3} 
 +$$
  
-== Bitwise NOT == +Exemplu:
-<spoiler Semnificație>​ +
-** Bitwise NOT ** (** complement față de 1 **) este operația la nivel de bit care următorul tabel de adevăr. +
-^ x ^ ~x ^ +
-^ 0 ^ 1 ^ +
-^ 1 ^ 0 ^+
  
-Evident putem extinde această operație și la nivel de număr. Operația se aplică separat pentru fiecare rang binar. +$$ 
-^  ^ $b_2 $b_1$ ^ $b_0$ ^ +  \Large 
-^ x = 3 ^ ^ +   
-^ ~x 4 ^ ^ +  \begin{bmatrix} 
-</​spoiler>​+     1 & & 2 \\  
 +     -& 3 & 
 +  ​\end{bmatrix} 
 +\cdot 
 +  \begin{bmatrix}  
 +    3 & 1 \\  
 +    2 & 1 \\  
 +    1 & 0 
 +  \end{bmatrix} 
 += 
 +\begin{bmatrix} 
 +   \times 3 + \times 2 + 2 \times 1 & 1 \times 1 + \times 1 + 2 \times 0 \\ 
 +  -1 \times 3 + 3 \times 2 + 1 \times 1 & -1 \times 1 + 3 \times 1 + 1 \times 0  
 +\end{bmatrix} 
 +
 +\begin{bmatrix} 
 +    5 & 1 \\ 
 +    4 & 2 
 +\end{bmatrix} 
 +$$
  
-== Bitwise AND == +=== Reprezentarea în memorie ===
-<spoiler Semnificație>​ +
-** Bitwise AND ** (** ȘI pe biți **) este operația la nivel de bit care următorul tabel de adevăr. +
-^ x ^ y ^ x & y ^ +
-^ 0 ^ 0 ^ 0 ^ +
-^ 0 ^ 1 ^ 0 ^ +
-^ 1 ^ 0 ^ 0 ^ +
-^ 1 ^ 1 ^ 1 ^+
  
-Evident putem extinde această operație șla nivel de numărOperația ​se aplică separat ​pentru ​fiecare rang binar+Cunoaşterea reprezentării în memorie a tablourilor vă ajută să înţelegeţmai bine cum se lucrează cu aceste tipuri ​de date şi să evitaţi atât erorile comune, cât şi pe cele mai subtileAşa cum se ştie, fiecare variabilă are asociata o anumită adresă în memorie şi ocupă o anumită lungime, măsurată în octeţi. Standardul C impune ca un tablou să fie memorat într-o zonă continuă de memorie, astfel ca pentru ​un tabloul de forma: ''​T tab[dim1][dim2]...[dimn];''​ 
-^  ^ $b_2$ ^  $b_1$ ^ $b_0$ ^ +dimensiunea ocupată în memorie va fi ''​sizeof(T)*dim1*dim2*...*dimn''​. Vom considera în continuare cazul particular al unui vector vect de lungime n, şi al unui element oarecare al acestuia, de pe pozitia i. 
-^ x = 3 ^ 0 ^ 1 ^ 1 ^ +Atunci când întalneşte numele vect, compilatorul va intelege ''"​adresa în memorie de la care începe vectorul vect"''​. Operatorul de indexare [] aplicat numelui vect instruieşte compilatorul să ''"​evalueze acel element de tipul T, care se află pe pozitia i în vectorul care începe de la adresa vect"''​. Acest lucru se poate exprima direct: ''"​evaluarea variabilei de tip T de la adresa vect + i * sizeof(T)"''​.
-^ y = 7 ^ 1 ^ 1 ^ 1 ^ +
-^ x & y = 3 ^ 0 ^ 1 ^ 1 ^ +
-</​spoiler>​+
  
-== Bitwise OR == +În ultima formulare observaţca nu mai intervine sub nici o formă dimensiunea vectorului dată la declarare. Aceea a fost necesară doar compilatorului,​ ca sa ştie câtă memorie să aloce pentru reprezentarea acestuia. De asemenea, observaţi că sunt permise indexari în afara spaţiului ​de memorie alocat, şi astfel programul va putea, din greşeala, accesa alte zone de memorie, lucru care poate avea repercursiuni grave. În cel mai bun caz programul nostru se va comporta foarte ciudat (erori în locuri total imprevizibile),​ şi în cel mai rău caz întreg sistemul va fi blocat (în cazul sistemelor care nu au implementate spaţii virtuale ​de memorie proprii fiecărei aplicaţii - platformele Windows NT si Linux).
-<spoiler Semnificație>​ +
-** Bitwise OR ** (** SAU pe biț**) este operația ​la nivel de bit care următorul tabel de adevăr. +
-^ x ^ y ^ x | y ^ +
-^ 0 ^ 0 ^ 0 ^ +
-^ 0 ^ 1 ^ 1 ^ +
-^ 1 ^ 0 ^ 1 ^ +
-^ 1 ^ 1 ^ 1 ^+
  
-Evident putem extinde această operație șla nivel de număr. Operația se aplică separat pentru fiecare rang binar. +Faptul că graniţa dintre vectori şadrese ​de memorie este atât de fină în limbajul C, sintaxa acestuia permite expresii ciudate, de forma:
-^   ^ $b_2$  ^  $b_1$ ^ $b_0$ ^ +
-^ x ^ 0 ^ 1 ^ 1 ^ +
-^ y ^ 1 ^ 0 ^ 1 ^ +
-^ x & y = 7 ^ 1 ^ 1 ^ 1 ^ +
-</​spoiler>​+
  
-== Bitwise XOR == +<code c
-<spoiler Semnificație+char a[100]; 
-** Bitwise XOR ** (** SAU-EXCLUSIV pe biți **) este operația la nivel de bit care următorul tabel de adevăr. +a[0] = 1; 
-^ x ^ y ^ x ^ y ^ +3[a] = 5; 
-^ 0 ^ 0 ^ +</​code>​
-^ 0 ^ 1 ^ ^ +
-^ 1 ^ 0 ^ 1 ^ +
-^ 1 ^ 1 ^ 0 ^+
  
-Evident putem extinde această operație șla nivel de numărOperația se aplică separat pentru fiecare rang binar. +Instrucţiunea din urmă înseamna pur şsimplu "​asignează 5 variabilei de tip char de la adresa 3 + a * sizeof(char) = 3 + a"Observaţi că aceasta este echivalentă cu a[3= 5;
-^       ^ $b_2$ ^  $b_1$ ^ $b_0$ ^ +
-^ x = ^ 0 ^ 1 ^ 1 ^ +
-^ y = 5 ^ 1 ^ 0 ^ 1 ^ +
-^ x %%^%% y = 6 ^ 1 ^ 1 ^ 0 ^ +
-</​spoiler>​+
  
-== Bit LOGICAL SHIFT == +De asemenea, un alt avantaj apare la definirea unui parametru al unei funcţii, de tip vector, caz în care nu este necesară precizarea dimensiunii acestuia: 
-În C sunt definite doar shiftări logice. Acestea pot fi la stânga ​(%%<<​%%) sau la dreapta (%%>>​%%)reprezentând deplasarea in binar a cifrelor și completarea pozițiilor "​golite"​ cu zerouri.+void sort(int[] vectn);
  
-== LEFT SHIFT == +<​note>​ 
-<​note>​  +Este de remarcat faptul că pentru **tablouri de dimensiuni m > 1**, este necesară precizarea **lungimilor ultimelor m - 1 dimensiuni**,​ pentru ca compilatorul să poată calcula adresa fiecărui element atunci când acesta este referit în program
-Efectul unei deplasări la stânga cu un rang binar este echivalent cu înmulțirea cu 2 a numărului din baza 10+Mai multe detalii legate ​de reprezentarea tablourilor şi, în general, a datelor în memorie, vor fi date în laboratorul 8.
-Dacă rezultatul nu are loc pe tipul de date folosit, atunci se pot pierde din biți+
- +
-Se poate deduce următoarea relație: $ n << k = n * 2^k $.+
 </​note>​ </​note>​
  
-<spoiler Exemplu>​ +=== Exemple ​de programe ​===
-Fie un exemplu ​de deplasarea la stânga, pentru un număr ** pe 3 biți **.  +
-^            ^ $b_2$ ^  $b_1$ ^ $b_0$ ^ +
-^ x 3      ^ 0 ^ 1 ^ 1 ^ +
-^ x << 1 6 ^ 1 ^ 1 ^ 0 ^ +
-^ x << 2 8 ^ 1 ^ 0 ^ 0 ^ +
-</​spoiler>​+
  
-== RIGHT SHIFT == +  * Declararea unei matrici unitate: 
-<note>  +<code c
-Efectul unei deplasări la dreapta cu un rang binar este echivalent cu împărțirea întreagă la 2 a numărului din baza 10.+#define M 20 /* nr maxim de linii si de coloane */
  
-Se poate deduce următoarea relațien >> k [/ 2^k $. +int main() { 
-</note>+  float unit[M][M];​ 
 +  int i,j,n; 
 +     
 +  printf("​nr.linii/​coloane"); 
 +  scanf("​%d",​ &n); 
 +  if (n > M) { 
 +    return; 
 +  } 
 +     
 +  for (i 0; i < n; i++) { 
 +    for (j = 0; j < n; j++) { 
 +      if (i != j) { 
 +        unit[i][j]=0; 
 +      } else { 
 +        unit[i][j]=1;​ 
 +      } 
 +    } 
 +  } 
 +    
 +  return 0; 
 +} 
 +</code>
  
-<spoiler Exemplu>​ +  ​Citire/scriere de matrice de reali:
-Fie un exemplu de deplasarea la dreapta, pentru un număr ​** pe 3 biți **.  +
-^  ^ $b_2$ ^  $b_1$ ^ $b_0$ ^ +
-^ x = 3 ^ 0 ^ 1 ^ 1 ^ +
-^ x >> 1 = 1 ^ 0 ^ 0 ^ 1 ^ +
-^ x >> 2 = 0 ^ 0 ^ 0 ^ 0 ^ +
-</spoiler>+
  
- +<code c> 
- +int main() { 
- +  int nl, nc, i, j; 
-==== Lucrul cu măști ==== +  ​float a[20][20];
-Având la dispoziție operațiile prezentate mai susputem răspunde la următoarele întrebări. +
- +
-  * Cum verificăm dacă ** bitul ** dintr-un număr n este ** setat **? +
-  ​* Cum ** setăm bitul i ** dintr-un număr n? +
-  * Cum ** resetăm bitul i ** dintr-un număr n?+
   ​   ​
-Pentru a răspunde ușorpentru fiecare întrebare vom aplica o operație pe biți între ​șo valoarea numită ​** mască **.+  /* Citire de matrice */ 
 +  printf("​nr.linii:​ "); 
 +  scanf("​%d"​&nl); 
 +  printf("​nr.coloane:​ "); 
 +  scanf("​%d",​ &nc); 
 +     
 +  if (nl > 20 || nc > 20) { 
 +    printf("​Eroare:​ dimensiuni > 20 \n"); 
 +    return ; 
 +  } 
 +     
 +  for (= 0; i < nl; i++) { 
 +    for (j = 0; j < nc; j++) { 
 +      scanf("​%f",​ &​a[i][j]);​ 
 +    } 
 +  } 
 +     
 +  /Afisare matrice ​*
 +  for (i = 0; i < nl; i++) { 
 +    for (j = 0; j < nc; j++) { 
 +      printf("​%f ",​a[i][j]);​ 
 +    } 
 +    printf ("​\n"​);​ 
 +  } 
 +   
 +  return 0; 
 +
 +</​code>​
  
 +==== Erori comune ====
  
 +  * Inversarea indicilor pentru elementele unei matrice sau tablou. E usor sa-l inversezi pe i cu j in expresia A[i][j] astfel ca trebuie sa fiti atenti cand scrieti astfel de cod. Luati in considerare si folosirea de nume mai sugestive pentru variabile. ​
  
 +===== Referinţe =====
 +[[http://​en.wikipedia.org/​wiki/​Matrix_multiplication | Wikipedia - Matrix Multiplication]]
  
-=== Cum verificăm dacă  bitul i  dintr-un număr n este setat? === +[[http://​ocw.cs.pub.ro/​courses/​so/​laboratoare/​resurse/​gdb | GDB Tutorial]]
-<spoiler Explicație>​+
  
-Această întrebare ne oferă valoarea bitului i.+==== Exerciții Laborator CB/CD ==== 
 +Primul exercitiu presupune modificarea/​adaugarea de instructiuni unui cod existent pentru a realiza anumite lucruri. In momentul actual programul realizeaza transpunerea unei matrice patratice primite ca parametru. Se afiseaza atat matricea initiala, cat si matricea transpusa. 
 +    *Nu uitati ca trebuie sa utilizam un [[http://​ocw.cs.pub.ro/​courses/​programare/​coding-style| coding style]] adecvat atunci cand scriem sursele.
  
-Dacă "​valoarea este 1", atunci vom spune că "bitul este setat"+<​code ​ex1.c>
  
-Dacă "​valoarea este 0", atunci vom spune că "bitul nu este "​setat"​.+#include <stdio.h>
  
 +#define N 100
  
-Pentru a ** verifica ** valoarea bitului i din numărul n, practic noi ar trebui să privim numărul astfel: 
  
-^    ^ $b_7$ ^ $b_6$ ^ ... ^ $b_i$ ^ ... ^ $b_1$ ^ $b_0$ ^ +void transpose_matrix(int m[N][N], int n
- ^ *  ^  * ^ ... ^  ? ^ ... ^ *  ^  * ^+
 + int i, j, tmp;
  
-unde ***** înseamnă ** don't care ** (de la PL), + for (i = 0; i < n; i++{ 
-iar **?** este valoarea pe care o cautăm.+ for (j = i + 1; j < n; j++) { 
 + tmp = m[i][j]; 
 + m[i][j] = m[j][i]; 
 + m[j][i] = tmp; 
 +
 +
 +}
  
-Deci am vrea sa facem, după cum am zis mai sus, o operație de tipul "​scoate"​ doar bitul i din număr, iar în rest lasă 0 (pentru a evidenția bitul nostru). 
-^            ^ $b_7$ ^ ... ^ $b_{i+1}$ ​ ^ $b_i$ ^ $b_{i-1}$ ^ ... ^ $b_0$ ^    ^ 
-^         ​n ​ ^ *     ^ ... ^  *         ​^ ​ ?    ^  *        ^ ... ^  *    ^    ^ 
-^      mask  ^ $m_7$ ^ ... ^ $m_{i+1}$ ​ ^ $m_i$ ^ $m_{i-1}$ ^ ... ^ $m_0$ ^ op ^ 
-^ n op mask  ^ 0     ^ ... ^  0         ​^ ​ ?    ^  0        ^ ... ^  0    ^    ^ 
  
-Să analizăm cine pot fi **op** și **biții din mască** ​($m_i$).+void print_matrix(int m[N][N], int n) 
 +
 + int i, j;
  
-Dorim ca: + for (i 0; < n; i++) { 
-  * $ ? \ \ op \ \ m_i \ ? $ : operația op aplicată pe $?$ ș$m_i$, va avea mereu ca rezultat pe $?$. + for (j = 0; j < n; j++) { 
-  * $ * \ \ op \ \ m_j = 0 (unde != j) : operația op aplicată pe orice valoare și $m_j$, va da 0.+ printf("%d ", m[i][j])
 +
 + printf("​\n"​);​ 
 +
 + printf("​\n"​);​ 
 +}
  
-Observăm că: 
-  * 1 este elementul neutru pentru **ȘI**, ceea ce verifică ** ? & 1 = ? **, oricare are fi ? un bit. 
-  * 0 este elementul care poate "​șterge"​ un bit prin **Și**, ceea ce verifică ** * & 0 = 0 **, oricare ar fi * un bit. 
  
-</​spoiler>​ +int main(void) 
-<​note>​ +{ 
-Detectarea bitului:+ int i, n = 3;
  
-  * pas 1: se aplică următoarea operația ** x n & mask **, unde ** mask = (<< i) **+ int V[N][N] ​
 + {1, 2, 3}, 
 + {4, 5, 6}, 
 + {7, 8, 9} 
 + };
  
-^       ^ $b_7$ ^ ... ^ $b_{i+1}$ ​ ^ $b_i$ ^ $b_{i-1}$ ^ ... ^ $b_0$ ^    ^ + print_matrix(V,​ n); 
-^    ​ ^ *     ^ ... ^  *         ​^ ​ ?    ^  *        ^ ... ^  *    ^    ^ + transpose_matrix(V, ​n); 
-^ mask  ^ 0     ^ ... ^  0         ​^ ​ 1    ^  0        ^ ... ^  0    ^ op ^ + print_matrix(V,​ n);
-^    x  ^ 0     ^ ... ^  0         ​^ ​ ?    ^  0        ^ ... ^  0    ^    ^+
  
 + return 0;
 +}
  
-  * pas 2: deoarece **?** poate avea două valori, x poate fi $0$ sau $2^i$. +</code>
-         * dacă ** x == 0 **, atunci ** bitul i este 0 ** +
-         * dacă ** x > 0  **, atunci ** bitul i este 1 **  +
-</note>+
  
 +Cerinte:
 +  *Realizati citirea unei matrice patratice de la tastatura - se va suprascrie n.
 +  *Realizati suma elementelor de deasupra diagonalei principale.
 +  *Afisati elementele de sub diagonala secundara. In locul elementelor de deasupra diagonalei secundare se va afisa 0.
  
-<spoiler Implementare C> 
-<code C> 
  
 +**Următoarele două probleme vă vor fi date de asistent în cadrul laboratorului.**
  
-// is_set +[[https://drive.google.com/file/d/​1u5l6ouDLRZ5WGrG8YV-iHYXqo3S6aRu9/​view?​usp=sharing|Checker laborator 6]] 
-// byte    ​byte de intrare pentru care vreau sa verific un bit +[[ https://ocw.cs.pub.ro/courses/programare/checker | Tutorial folosire checker laborator ]]
-// i       - indexul bitului din byte +
-// @return - 1, daca bitul este 1 +
-//           0, daca bitul este 0 +
-int is_set(char byte, int i) { +
-    int mask = (1 << i); +
-    return (byte & mask) != 0; +
-}+
  
-... 
-if (is_set(mybyte,​ i)) { 
-    printf("​bitul %d din byteul %d este setat!\n",​ i, mybyte); 
-} else { 
-    printf("​bitul %d din byteul %d NU este setat!\n",​ i, mybyte); 
-} 
-... 
-</​code>​ 
-</​spoiler>​ 
  
  
  
  
-=== Cum setăm (valoarea devine 1)  bitul i  dintr-un număr n? === +<hidden
-<spoiler Explicație+Link direct către lista completă de probleme[[https://​docs.google.com/​document/​d/​1DVe0rJnfZUHU6iOn8rh03ybG5w7Af-HB4BCx7KnJsks/​edit|aici]] 
-Dorim să facem următoarea operațieschimba doar bitul i in 1, iar pe ceilalți lasă-i neschimbați. +</​hidden>​
-^            ^ $b_7$ ^ ... ^ $b_{i+1}$ ^ $b_i$ ^ $b_{i-1}$ ^ ... ^ $b_0$ ^    ^ +
-^         ​n ​ ^ $n_7$ ^ ... ^ $n_{i+1}$ ^  *    ^ $n_{i-1}$ ^ ... ^ $n_0$ ^    ^ +
-^      mask  ^ $m_7$ ^ ... ^ $m_{i+1}$ ^ $m_i$ ^ $m_{i-1}$ ^ ... ^ $m_0$ ^ op ^ +
-^ n op mask  ^ $n_7$ ^ ... ^ $n_{i+1}$ ^  1    ^ $n_{i-1}$ ^ ... ^ $n_0$ ^    ^+
  
-Să analizăm cine pot fi **op** și **biții din mască** ($m_i$). 
  
-Dorim ca: +===== Exerciții de Laborator seria CB =====
-  * $ * \ \ op \ \ m_i 1 $ : operația op aplicată pe $*$ (orice) și $m_i$, va avea mereu ca rezultat pe $1$. +
-  * $ n_j \ \ op \ \ m_j n_j $ (unde i !j) : operația $op$ aplicată pe orice valoare și $m_j$, va da $n_j$.+
  
-Observăm că+    - [2p] Următorul program ar trebui să citească și să afișeze o matrice. Compilați și rulați
-  * 1 esteelementul care poate "​umple"​ un bit prin **SAU**, ceea ce verifică $ * | 1 = 1 $, oricare ar fi * un bit+<code c matrix.c> 
-  * 0 este elementul neutru pentru **SAU**, ceea ce verifică $ n_j | 0 = n_j $, oricare are fi $n_j$ un bit+#​include ​<stdio.h>
-</spoiler>+
  
-<​note>​ +#define MAX 100
-Setarea bitului: +
-  * pas 1: se aplică următoarea operația ** x = n | mask **, unde ** mask = (1 << i) **+
  
-^            ^ $b_7$ ^ ... ^ $b_{i+1}$ ^ $b_i$ ^ $b_{i-1}$ ^ ... ^ $b_0$ ^    ^ +void read_matrix(int a[MAX][MAX],​ int n) 
-^         ​n ​ ^ $n_7$ ^ ... ^ $n_{i+1}$ ^  *    ^ $n_{i-1}$ ^ ... ^ $n_0$ ^    ^ +
-^      mask  ^ $0  $ ^ ... ^ $0      $ ^ $1  $ ^ $0      $ ^ ... ^ $0  $ ^ op ^ + int i, j;
-^ n op mask  ^ $n_7$ ^ ... ^ $n_{i+1}$ ^  1    ^ $n_{i-1}$ ^ ... ^ $n_0$ ^    ^+
  
 + scanf("​%d",​ &n);
 + for (i = 0; i < n; i++)
 + for (j = 0; j < n; j++)
 + scanf("​%d",​ &​a[i][j]);​
 +}
  
-  * explicație:​ +int main(void) 
-         * orice valoare are avea bitul $*$ va fi suprascris cu 1 +
-         * ceilalti biți vor fi copiați+ int a[MAX][MAX],​ n = 1i, j;
  
-</​note>​+ read_matrix(a,​ n);
  
-<spoiler Implementare C> + for(i = 0; i n; i++) { 
-<code C>+ for (j = 0; j n; j++) 
 + printf("​%d ", a[i][j]); 
 + printf("​\n"​);​ 
 + }
  
-// set + return ​0;
-// byte    - byte de intrare pentru care vreau sa setez un bit +
-// i       - indexul bitului din byte +
-// @return ​- noul byte +
-char set(char byte, int i) { +
-    int mask = (1 << i); +
-    return (byte | mask);+
 } }
- 
-... 
-mybyte = set(mybyte, i); 
-... 
-    ​ 
 </​code>​ </​code>​
-</spoiler>+    * ce observați?​ 
 +    * folosind printf, afișați după apelul ''​read_matrix''​ valoarea lui ''​n''​ și a lui ''​a[0][0]''​ 
 +    * identificați problema 
 +    * rezolvați problema  
 +  - [3p] Următorul program inversează elementele unui vector. Compilați și rulați. 
 +<code c swap.c>​ 
 +#include <stdio.h>
  
 +#define MAX 100
  
 +void magic(int a[MAX], int n)
 +{
 + int i;
  
 + for (i = 0; i < n; i++)
 + a[i] = a[i] & (~(0x01 & 0x42));
  
 + for (i = 0; i < n/2; i++) {
 + a[i] = a[i] ^ a[n - i];
 + a[n - i] = a[i] ^ a[n - i];
 + a[i] = a[i] ^ a[n - i];
 + }
  
-=== Cum resetăm ​(valoarea devine 0)  bitul  ​dintr-un număr n? === + for (i = 0ni++); 
-<spoiler Explicație>​ + a[i] = a[i] & (~(0x42 & 0x101));
-Dorim să facem următoarea operație: schimba doar bitul i in 0, iar pe ceilalțlasă-i neschimbați. +
-^            ^ $b_7$ ^ ... ^ $b_{i+1}$ ^ $b_i$ ^ $b_{i-1}$ ^ ... ^ $b_0$ ^    ^ +
-^          ^ $n_7$ ^ ... ^ $n_{i+1}$ ^  *    ^ $n_{i-1}$ ^ ... ^ $n_0$ ^    ^ +
-^      mask  ^ $m_7$ ^ ... ^ $m_{i+1}$ ^ $m_i$ ^ $m_{i-1}$ ^ ... ^ $m_0$ ^ op ^ +
-^ n op mask  ^ $n_7$ ^ ... ^ $n_{i+1}$ ^  0    ^ $n_{i-1}$ ^ ... ^ $n_0$ ^    ^+
  
-Să analizăm cine pot fi **op** și **biții din mască** ($m_i$).+}
  
-Dorim ca: +int main(void) 
-  * $ * \ \ op \ \ m_i = 0 $ : operația op aplicată pe $*$ (oriceși $m_i$va avea mereu ca rezultat pe $0$. +
-  * $ n_j \ \ op \ \ m_j = n_j $ (unde != j) : operația $op$ aplicată pe orice valoare și $m_j$, va da $n_j$.+ int a[MAX], n, i;
  
-Observăm că: + for (i = 0; i < n; i++) { 
-  * 0 este elementul care poate "șterge" ​un bit prin **ȘI**ceea ce verifică $ * 0 = 0 $, oricare ar fi * un bit. + scanf("%d", &a[i]); 
-  * 1 este elementul neutru pentru **ȘI**, ceea ce verifică $ n_j | 1 = n_j $, oricare are fi $n_j$ un bit. + }
-</​spoiler>​+
  
-<​note>​ + magic(a, n);
-Resetarea bitului:+
  
-  * pas 1: se aplică următoarea operația ** x = n | mask **, unde ** mask = ~(1 << ​i) **+ for (i 0; i < n; i++); { 
 + printf("%d ", a[i])
 + }
  
-^            ^ $b_7$ ^ ... ^ $b_{i+1}$ ^ $b_i$ ^ $b_{i-1}$ ^ ... ^ $b_0$ ^    ^ + return ​0;
-^         ​n ​ ^ $n_7$ ^ ... ^ $n_{i+1}$ ^  *    ^ $n_{i-1}$ ^ ... ^ $n_0$ ^    ^ +
-^      mask  ^ $1  $ ^ ... ^ $1      $ ^ $ $ ^ $1      $ ^ ... ^ $1  $ ^ op ^ +
-^ n op mask  ^ $n_7$ ^ ... ^ $n_{i+1}$ ^  0    ^ $n_{i-1}$ ^ ... ^ $n_0$ ^    ^ +
- +
- +
-  * explicație:​ +
-         * orice valoare are avea bitul $*$ va fi suprascris cu 0 +
-         * ceilalti biți vor fi copiați +
- +
-</​note>​ +
- +
- +
-<spoiler Implementare C> +
-<code C> +
- +
-// reset +
-// byte    - byte de intrare pentru care vreau sa resetez un bit +
-// i       - indexul bitului din byte +
-// @return - noul byte +
-char reset(char byte, int i) { +
-    int mask = ~(1 << i); +
-    return (byte & mask);+
 } }
- 
-... 
-mybyte = reset(mybyte,​ i); 
-... 
-    ​ 
 </​code>​ </​code>​
-</​spoiler>​+    * folosiți gdb pentru a identifica și rezolvați problemele 
 +    - Scrieţi un program pentru înmulţirea a două matrice, dacă aceasta este posibilă. Va trebui să implementaţi două funcţii:​\\ 
 +    * [1p] una pentru citirea unei matrice într-un tablou bidimensional,​ dat ca parametru. 
 +    * [2.5p] una care să realizeze efectiv înmulţirea a două matrice. 
 +    - [1.5p] Scrieţi un program care ridică o matrice patratică cu n linii şi n coloane la puterea p, cu p număr întreg pozitiv.
  
 +===== Exerciţii de Laborator =====
 +  * **Exercitiul 1 [2 pct]:** Citiți de la tastatură o matrice (puteți hardcoda dimensiunea maximă a matricei). Afișați matricea transpusă.
 +<​code>​
 +Exemplu:
  
-==== Exerciții ​ ==== +Input 2 4 // număr de linii urmat de număr de coloane din matrice 
-[[https://drive.google.com/​drive/​folders/​0BworQDqcRK0yd205cE1qamZ5bEU|Checker laborator ​CB\CD]]+                1 2 3 4 
 + 5 6 8
  
-==Precizari:==+Output: 1 5 
 + 2 6 
 + 3 7 
 + 4 8 
 +</​code>​ 
 +  * **Exercitiul 2 [2 pct]:** Citiți de la tastatură 2 matrice (puteți hardcoda dimensiunea maximă a matricelor) – prima matrice numită în continuare A, iar a doua B. Determinați dacă este posibilă operația de înmulțire de matrice folosind drept operanzi cele două matrice. Determinați toate rezultatele posibile și afișati-le la consolă, precizând ordinea în care s-au înmulțit operanzii. Dacă nu se poate efectua nicio operație de înmulțire,​ afișați mesajul „Nu se poate efectua operatia de inmultire cu aceste matrice!”. 
 +<​code>​ 
 +Exemplu:
  
 +Input: 2 2 // număr de linii urmat de număr de coloane din matricea A
 +                1 2
 + 3 4
 + 2 2 // număr de linii urmat de număr de coloane din matricea B
 +                5 6
 + 7 8
  
-    ​Arhivele 4, 5, 6 testeaza reuniunea, intersectia respectiv diferenta seturilor. +Output: A B 
-    * Intrarea corespunde functiei set_read (n, urmat de n elemente) + 19 22 
-    * Ref corespunde functiei set_print aplicata pe setul obtinut (cardinalul setului, urmat pe urmatoarea linie de elementele din set)+ 43 50
  
-    ​Arhiva 7 corespunde problemei ​de bonus B1 (.ref contine rezultatul pentru get_lsb urmat de rezultatul ​pentru get_msb) +
-    * Arhiva 8 corespunde problemei B2.+ 23 34 
 + 31 46 
 +</​code>​ 
 +  * **Exercitiul 3 [2 pct]:** Folosind logica funcției implementată anterior, implementați operația ​de ridicare la putere a unei matriceCitiți ​de la consolă matricea, respective puterea la care trebuie ridicată matricea. Afișați la consolă ​rezultatul ​obținut sau mesajul “Operatie invalida” in caz contrar. 
 +<​code>​ 
 +Exemplul 1:
  
 +Input: 2 2 // număr de linii urmat de număr de coloane din matrice
 +                1 2
 + 3 4
 + 3 // puterea la care trebuie ridicată matricea anterioară
  
 +Output: 37 54
 + 81 118
  
 +Exemplul 2:
  
-<note warning>​ +Input: 2 3 // număr de linii urmat de număr de coloane din matrice 
-În rezolvarea acestui ** laborator ** nu aveți voie să folosiți operatorii ** /, *, % ** !+                1 2 3 
 + 4 5 6 
 + 3 // puterea la care trebuie ridicată matricea anterioară
  
-HintÎncercați să folosiți operații pe biți!  +Output Operatie invalida
-</​note>​ +
- +
-Rezolvați împreună cu asistentul, eventual pe tablă, următoarele 3 exerciții. +
- +
-== 1. Calcul putere a lui 2 (0p) == +
-Să se scrie o funcție care să calculeze $2^n$, unde $ n <= 30 $. +
-<code C> +
-int pow2(int n);+
 </​code>​ </​code>​
-Răspundeți la întrebarea: ​**are sens** să scriem ​o funcție?+  ​* **Exercitiul 4 [2 pct]:** Citiți o matrice pătratică de la tastatură. Intersecția diagonalelor matricei, formează 4 zone „triunghiulare” în matrice. Implementați ​o funcție ​care primește ca parametru o matrice pătratică și dimensiunea laturii acesteia și afișează elementele aflate în triunghiul superior. 
 +<​code>​ 
 +Exemplul 1:
  
-== 2. Negarea biților unui număr n (0p) == +Input: 4 // dimensiunea laturii matricei 
-Să se scrie o funcție care să nege biții unui număr n (32 biți). +                1 3 4 
-<code C> + 5 6 7 8 
-int flip_bits(int n); + 9 0 1 2 
-</​code>​ + 3 4 5 6
-Răspundeți la întrebarea:​ **are sens** să scriem o funcție?+
  
-== 3. Afișarea biților unui număr n (0p)== +Output: 1 2 4 
-Să se scrie o funcție care să afișeze toți biții unui număr întreg pe 32 biți. + 6 7
-<code C> +
-void print_bits(int n); +
-</​code>​+
  
-Implementați invidual următoarea problemă. 
-== 4. bitset (10p) == 
-O mulțime de numere întregi poate fi reprezentată astfel: spunem că un număr aparține unei mulțimi S dacă bit-ul al i-lea din vectorul S are valoarea 1.  
  
-Pentru e ficientă,​ vectorul S va conține date de tipul **unsigned char**. 
  
-<spoiler Exemplu> 
-Presupunem că avem vectorul ** unsigned char S[3]; **, pentru care am initializat deja valorile cu 0, 3, 5. 
-S[0], S[1], S[2] fiecare reprezintă câte o variabilă pe 8 biți. 
  
-^  ^     ​^ ​    ​^ ​    ​^ ​  ​S[0] ​ ^     ​^ ​    ​^ ​    ​^ ​    ​^ ​ |   ​^ ​    ​^ ​    ​^ ​    ^ S[1]    ^     ​^ ​    ​^ ​    ​^ ​    ​^ ​  ​| ​ ^     ​^ ​    ​^ ​    ^ S[2]    ^     ​^ ​    ​^ ​    ​^ ​    ^ 
-^ ^$b_0$^$b_ 1$^$b_2$^$b_3$^$b_4$^$b_5$^$b_6$^$b_7$^ ​ |   ^ $b_0$^$b_1$^$b_2$^$b_3$^$b_4$^$b_5$^$b_6$^$b_7$^ ​ |   ^ $b_0$^$b_1$^$b_2$^$b_3$^$b_4$^$b_5$^$b_6$^$b_7$^ 
-^ biti din S ^0    ^0    ^0    ^0    ^0    ^0    ^0    ^0    ^  |  ^1    ^1    ^0    ^0    ^0    ^0    ^0    ^0    ^    |   ^ 1    ^0    ^1    ^0    ^0    ^0    ^0    ^0    ^ 
-^ numere asociate^0^1^2^3^4^5^6^7^ | ^8^9^10^11^12^13^14^15^ | ^16^17^18^19^20^21^22^23^ ​ 
  
-<​note>​ 
-Atentie! Bitii au fost desenati invers (stanga-dreapta 0-7) pentru a obtine in desen sirul sortat de numere asociate. 
-In realitate un byte arata asa: $b_7b_6b_5b_4b_3b_2b_1b_0$ 
-</​note>​ 
-Observați notarea biților! Vom folosi această schema pentru a obține șirul numerelor asociate ca fiind sortat. 
  
-Interpretare:+Exemplul 2:
  
-- numărul **3** nu face partea din mulțimea S, pentru că bitul asociat (**cel cu numărul ​etichete ​3** din vector) este **0**+Input: 3 // dimensiunea laturii matricei 
 +                1 2 3 
 + 4 5 6 
 + 7 8 9
  
-- numărul **16** face partea din mulțimea S, pentru că bitul asociat (**cel cu numărul / etichepa 16 ** din vector) este **1** +Output: 2 3 
- + 5
-Analog pentru toate numerele de la 0 la 23 (avem doar 24 de biți în acest exemplu), putem verifica dacă numărul i este în vector. +
-Astfel vectorul S de mai sus reprezintă mulțimea **{8, 9, 16, 18}**. +
- +
-Dacă programul nostru va seta bitul cu numărul 15 pe 1, atunci operația este echivalentă cu **S = S U {15}**. Programul va trebui să își dea seama ca **bitul cu numărul 15** este defapt ** bitul cu numărul 7 ** din **byteul cu numărul 1** (adica din S[1]).  +
-</​spoiler>​ +
- +
-<​note>​ +
-Pentru a folosi cu ușurință același cod facând schimbări minime (de exemplu schimbăm dimensiunea maximă a unei mulțimi), putem să ne definim propriul tip astfel: +
- +
-<code C> +
-#define SET_SIZE 100                   // aceasta este o macrodefiniție (momentan o putem privi ca pe O CONSTANTA CARE ARE VALOAREA 100 +
-typedef unsigned char SET[SET_SIZE]; ​  // definesc tipul SET, care este un vector cu maxim 100 de elemente de tip unsigned char+
 </​code>​ </​code>​
 +  * **Exercitiul 5 [2 pct]:** Se citesc două matrice de la tastatură. Verificați dacă a doua matrice este submatrice a primei matrice.
 +<​code>​
 +Exemplul 1:
  
-Cele două linii de mai sus vor fi puse imediat dupa includerea directivelor header!+Input: 2 2 // număr de linii urmat de număr ​de coloane din matricea A 
 +                1 2 
 + 3 4
  
-</note>+ 2 2 // număr de linii urmat de număr de coloane din matricea B 
 +                5 6 
 + 7 8
  
-    +Output Fals
-Implementați funcții pentru: +
-      * **adăugarea** unui element în mulțime (**1p**) +
-      <code C>  +
-      // set_insert(S,​n) - adauga numarul n in multimea S +
-      void set_insert(SET S, unsigned int n); +
-      </​code>​+
  
-      * **ștergerea** unui element din mulțime (**1p**) +Exemplul 2:
-      <code C> +
-      // set_delete(S,​n) - scoate numarul n din multime S +
-      void set_delete(SET S, unsigned int n); +
-      </​code>​+
  
-      * a verifica dacă un element n **aparține** unei mulțimi (**1p**) +Input: 2 2 // număr de linii urmat de număr de coloane din matricea A 
-      <​code C> +                2 
-      // set_has(S,​n) - returneaza ​daca n este in S, 0 altfel + 3 4
-      int set_has(SET S, unsigned int n); +
-      </​code>​+
  
-      * **ștergerea** tuturor elementelor din mulțime (**1p**) + 3 3 // număr de linii urmat de număr de coloane ​din matricea B 
-      <code C> +                5 6 4 
-      ​// set_delete_all(S) - elimina toate elementele ​din multime + 1 2 5 
-      void set_delete_all(SET S); + 3 4 6
-      </​code>​+
  
-      * a calcula **cardinalul** unei mulțimi (**1p**) +Output Adevarat
-      <code C> +
-      // set_card(S) - returneaza cardinalul multimii S +
-      int set_card(SET S); +
-      </​code>​ +
- +
-      * a verifica dacă mulțimea este **vidă** (**0.5p**) +
-      <code C> +
-      // set_is_empty(S) - verifica daca multimea este sau nu goala +
-      // returneaza 1 daca este, 0 daca nu este +
-      int set_is_empty(SET S); +
-      </​code>​ +
- +
-      * o funcție care **să citească de la tastatură** ​ o mulțime (**0.5p**) +
-      <code C> +
-      // set_read(A) - functia citeste numarul n de elemente care se afla in A +
-      // apoi citeste cele n numere si le insereaza in A +
-      // va returna numarul n citit (numarul de elemente) +
-      int set_read(SET A); +
-      </​code>​ +
- +
-      * o funcție care **să afișeze** pe ecran elementele care se află într-o mulțime (**0.5p**) +
-      <code C> +
-      // set_print(A) - functia printeaza elementele multimii A +
-      void set_print(SET A); +
-      </​code>​ +
- +
-Realizati un program care, utilizând metodele de fite anterior, citește 2 mulțimi A (n și B și a fișează$ A U B, A ∩ B, A - B, B - A $. +
- +
-Pentru a realiza acest lucru, va trebui să implementați următoarele funcții: +
-      * **reuniunea** a două mulțimi (**1p**) +
-      <code C> +
-      // C = AUB +
-      void set_reunion(SET A, SET B, SET C); +
-      </​code>​ +
- +
-      * **intersecția** a două mulțimi (**1p**) +
-      <code C> +
-      // C = AnB +
-      void set_intersection(SET A, SET B, SET C); +
-      </​code>​ +
- +
-      * **diferența** a două mulțimi (**1p**) +
-      <code C> +
-      // C = A - B +
-      void set_difference(SET A, SET B, SET C); +
-      </​code>​ +
- +
-În final va trebui sa creați o funcție ** main ** și să faceți un program care rezolvă cerința folosind funcțiile implementate. (**1p**) +
- +
-<spoiler Hint> +
-Folosiți funcțiile **set, reset, is_set ** definite în laborator. +
- +
-Implementați funcțiile din enunț în ordinea sugerată. +
-</​spoiler>​ +
- +
-=== BONUS === +
-== B1. MSB/LSB == +
-Să se scrie o câte o funcție pentru aflarea MSB(Most significant bit), respectiv LSB(Least significant bit), pentru un număr n pe 32 biți. +
-<code C> +
-int get_lsb(int n); +
-int get_msb(int n);+
 </​code>​ </​code>​
-<spoiler Hint> +  * **Bonus [2 pct]:** CSe citește o matrice A de la tastatură. Afișați la consolă o matrice B cu proprietatea că B[i][j] = max(A[0..i][0..j]), unde max(A[0..i][0..j]) înseamnă elementul maxim din submatricea A care are colțul stânga – sus în A[0][0] școlțul dreapta – jos în A[i][j]. 
-Analizați reprezentarea în baza 2 a lui n. +<code>
-</​spoiler>​ +
- +
-== B2. Verificare că un număr este putere al lui 2 == +
-Să se scrie funcție care verifică dacă un număr întreg n pe 32 bițeste puterea a lui 2Funcția va returna 1 dacă n este putere a lui 2, altfel. +
-<code C> +
-int is_power2(int n)+
-</​code>​ +
-<spoiler Hint> +
-Analizați reprezentarea în baza 2 a lui n (exn = 16 si n = 5). +
-</​spoiler>​ +
- +
- +
- +
- +
-==== Probleme de interviu ==== +
-Pentru cei interesați, recomandăm rezolvarea și următoarelor probleme, care sunt des întâlnite la interviuri. +
-<note warning>​ +
-Atenție! Problemele din această categorie au un nivel de dificultate ridicat, peste cel cerut la cursul de PC. +
- +
-Recomandăm totuși rezolvarea acestor probleme pentru cei care doresc să aprofundeze lucrul cu operații pe biți+
-</​note>​ +
- +
-<spoiler Swap bits> +
-Se dă un număr n natural pe 32 de biți. Se cere să se calculeze numărul obținut prin interschimbarea biților de rang par cu cel de rang impar. +
- +
-Exemplu: n = 2863311530 = > m = 1431655765 +
- +
-<​note>​ +
-Hint: Reprezentarea numerelor ​în baza 2 ([http://​www.binaryhexconverter.com/​decimal-to-binary-converter | convertor]])+
-</note> +
- +
-</​spoiler>​ +
- +
-<spoiler Element unic din șir>  +
-Fie un șir cu ** 2n + 1 ** numere întregi, dintre care n numere apar de câte 2 ore, iar unul singur este unic. +
-Să se gasească elementul unic.  +
 Exemplu: Exemplu:
-        n = 5 și sirul [1, 4, 4, 1, 5] 
-        Numărul unic este 5.  
-<​note> ​       ​ 
-Hint: Încercați să nu folosiți tablouri. 
-</​note>​ 
  
-Follow-up 1Șirul are $2*n + (2 * p + 1)$ numere. Se sție că un singur ​număr ​apare de un număr ​impar de ori (2p + 1), iar celelalte apar de un număr par de ori. Cum găsiți numărul care apare de un număr impar de ori?+Input 3 4 // număr de linii urmat de număr de coloane din matricea A 
 +                ​2 5 2  
 + 6 3 9 8 
 + 4 0 4 5
  
-Exemplu: +Output 5 5 
-        n = 5 și sirul [1, 1, 4, 4, 4, 4, 55, 5] + 6 6 9 9 
-        ​Răspunsul este 5. + 6 6 9 9
-          +
-Follow-up 2: Șirul are $2n + 2$ numere, n numere apar de câte 2 ori, iar 2 numere sunt unice. Cum găsiți cele 2 numer unice?+
  
-Exemplu: +</​code>​ 
-        n = 5 și sirul [1, 4, 4, 1, 5, 6] +<​hidden>​ 
-        ​Numărele unice sunt 5 și 6. +===== Soluții =====
  
-TODO: sursă ​        +</hidden>
-</spoiler>+
  
-<spoiler Căutare binară pe biți> +===== Referinţe ===== 
-Realizează o funcție de căutare pe binară, utilizând operații pe biți pentru optimizarea acestei implementări. +  ​* ​[[https://github.com/cs-pub-ro/ComputerProgramming/blob/master/Laboratories/Lab6/Lab6.pdf Cheatsheet matrici]]
- +
-Follow up: Puteți găsi alt algoritm care să nu se bazeze pe împarțirea vectorului în două și compararea elementului din mijloc cu cel cautat? +
- +
-<​note>​ +
- Hint: +
-[[http://www.infoarena.ro/problema/​cautbin | caut bin]] și [[http://​www.infoarena.ro/​multe-smenuri-de-programare-in-cc-si-nu-numai | Multe "​smenuri"​ de programare in C/C++... si nu numai!]] +
-</note> +
- +
-</spoiler>​ +
- +
-<spoiler Împărat, bețiv și nervos>​ +
-Împăratul Gigel a primit cadou ** 100 ** de sticle de vin de la un admirator secret. Acesta i-a lăsat și o scrisoare în care îi spune despre faptul că este vin nobil, însă a otrăvit o sticlă. Cine va bea din sticla otrăvită ** va muri în fix 24h **.  +
- +
-Gigel dispune de un număr imens de sclavi (precum număr imens de restanțe in Poli), așa că el își va pune sclavii să guste din vin. Se gândește totuși că nu se mai găsesc sclavi pe toate drumurile, așa ca dorește ** să folosească un număr minim de sclavi ** (cei care gustă riscă să moară). +
- +
-Ajutați-l pe Gigel să găsească numărul minim de sclavi pe care trebuie să îi foloseacă astfel: +
-   * pune pe cei **n sclavi** aleși la masă cu câte un pahar în mână, inițial gol +
-   * poruncește bucătarului să toarne vin în pahare, alegând cui și ce să toarne +
-   * unui sclav i poate turna în pahat vin din oricâte sticle (chiar și simultan) +
-   * după ce s-a turnat în **toate** cele n pahare, ei **vor bea toți simultan** +
-   * la finalul celor **24h** Gigel trebuie să își dea seama care este sticla otrăvită, altfel se va oftica și va pune 100 de sclavi să guste fiecare din câte o sticlă, iar pe cei care rămân în viață îi va împușca oricum pentru că e nervos +
- +
-P.S. Apreciați faptul că Gigel încearcă să nu omoare foarte mulți oameni degeaba. Ajutați-l să găsească $numărul minim n de sclavi$ care trebuie să guste din vin.  +
- +
-Follow-up: Aceeași problemă, dar pentru n sticle. +
- +
-TODO: sursă ​        +
- +
-<​note>​ +
-Hint: Reprezentarea numerelor în baza 2. +
-</note> +
- +
-</spoiler>​ +
- +
-<spoiler Jocul NIM>  +
-Se dau n grămezi, fiecare conţinând un anumit număr de pietre. Doi jucători vor începe să ia alternativ din pietre, astfel: la fiecare pas, jucătorul aflat la mutare trebuie să îndepărteze un număr nenul de pietre dintr-o singură grămadă. Câştigătorul este cel care ia ultima piatră. +
-Să se determine dacă jucătorul care ia primele pietre are strategie sigură de câştig. +
- +
-Exemple +
-       n = 4, gramezi = [1 3 5 7], raspuns = NU +
-       n = 3, gramezi = [4 8 17],  raspuns = DA +
- +
-<​note>​ +
-Hint: [[http://www.infoarena.ro/​problema/​nim ​nim]] +
-</​note>​+
  
-</​spoiler>​ 
programare/laboratoare/lab06.1510181142.txt.gz · Last modified: 2017/11/09 00:45 by darius.neatu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0