O problemă cu bits 1 Tiberiu Socaciu Enunţul Pe pagina Proful de Mate de pe Facebook 2 am primit de la un elev de clasa a IX-a următoarea provocare 3 : Vom oferi două soluţii, una folosind manipulări de bits, iar cealaltă manipulări de cifre în baza 2. Caracterele ca numere întregi Tipul char este un tip întreg fără semn pe un byte 4. Reprezentarea fiind în virgula fixă fără semn 5, valorile reprezentate sunt numere întregi cuprinse între 0 și 255. Aceste valori sunt codificările ASCII 6 ale caracterelor. Orice intrare sau orice ieșire a acestor date este la nivel de caracter 7, dar putem opera cu aceste date la nivel de număr întreg. De exemplu, dacă c este un char cu valoarea 1, atunci c+3 este 4. Dacă dorim să folosim o valoare întreagă pentru un char, putem folosi operatori de tip cast 8, ca în exemplul: char c= a ; cout << Vom afisa a: << c; 1 În acest articol preferăm pluralul englez; unii folosesc forma românizată biți. 2 Vezi [2]. 3 Vezi [1], pagina 15, problema 62, pentru problema originală. 4 Adică pe opt bits. 5 Adică direct în baza doi. 6 Inițial codul ASCII a fost doar pe 7 bits (se mai numește ASCII-7), ulterior, anumite sisteme de calcul // sisteme de operare / nivelul de după compilare / interpretare acceptând sau nu extensii. De exemplu, pentru C este ASCII-8, pe 8 bits, care poate fi, la limită, doar ASCII-7 cu al optulea bit pus pe zero. În Python, se foloseste o codificare de tip UNICODE, pe 2 bytes, interpretorul având sarcina de a fi pregătit pentru afișarea corectă (se folosește, de regulă. de capacitățile sistemului de operare, Linux sau Windows) 7 cin, cout, %c în printf și scanf etc. 8 Operatorii de tip cast sunt operatori unari care permit conversia dintr-un tip într-un alt tip, compatibil. 1
cout << Vom afisa codul lui a: << (int) c; Operaţii pe bits Limbajul C, ca limbaj definit pentru a scrie sisteme de operare 9 există suport spre instrucțiunile mașină care se traduc direct în instrucțiuni mașină 10. Într aceste operații sunt și operațiile pe bits, care sunt implementate în ALU 11, fiind utilizabile direct de procesor, la nivelul unei instrucțiuni mașină 12. Operațiile sunt SAU 13, ȘI 14, SAU- EXCLUSIV 15, NU 16, DEPLASARE-STÂNGA 17, DEPLASARE-DREAPTA 18, simbolurile acestora fiind &,, ^, ~, <<, >>. X Operaţie Y X operaţie Y sau Operaţie X a 1...a w & b 1...b w c 1...c w, unde: c i = a i & b i, cu i=1,w a 1...a w b 1...b w c 1...c w, unde: c i = a i b i, cu i=1,w a 1...a w ^ b 1...b w c 1...c w, unde: c i = a i ^ b i, cu i=1,w a 1...a w ~ c 1...c w, unde: c i = ~ a i, cu i=1,w a 1...a w << k c 1...c w, unde: c i-k = a i, cu i=k+1,w c w+1-i = 0, cu i=1,k a 1...a w >> k c 1...c w, unde: c i+k = a i, cu i=1,w+k c i = 0, cu i=1,k Explicaţie ŞI pe bits SAU pe bits SAU+EXCLUSIV pe bits NU pe bits DEPLASARE+STÂNGA pe bits DEPLASARE+DREAPTA pe bits Utilitatea operaţiilor pe bits Prezint în continuare câteva utilizări pentru operaţiile pe bits 19 : 1) a << k = a * 2 k 2) a >> k = a / 2 k (împărţire întreagă) 3) dacă a, b vector caracteristic, atunci a&b este vectorul caracteristic al intersecţiei 9 Sistemul de operare UNIX și derivate ale acestuia sunt scrise în limbajul C (doar o mică parte în limbaj de asamblare / limbaj mașină). 10 Vezi, spre exemplu, operatorii de incrementare (++), decrementare (--), operatorii cu acumulatorul (operator=) etc. 11 Unitate Aritmetică și Logică. 12 Care folosește ALU-ul direct, aceste operații fiind implementate hardware, cu porți logice. 13 Se mai foloseşte OR. 14 Se mai foloseşte AND. 15 Se mai foloseşte XOR. 16 Se mai foloseşte NOT. 17 Se mai foloseşte LEFT SHIFT. 18 Se mai foloseşte RIGHT SHIFT. 19 Vezi [3] pentru exemplificări. 2
4) dacă a, b vector caracteristic, atunci a b este vectorul caracteristic al reuniunii 5) dacă a vector caracteristic, atunci ~ a este vectorul caracteristic al complementului Constante pe bits Constantele întregi pot fi specificate direct in binar folosind construcţii de forma 20 0ba 1 a 2...a n, unde a 1 a 2...a n sunt cifre de 0 sau 1, iar secvența a 1 a 2...a n este completată cu zero-uri până la atingerea lui 8*sizeof(T), unde T este cast-ul implicit 21 sau explicit. Astfel 0b00000000 și 0b11111111 sunt constantele aferente lui (char) 0 și (char) 255. O soluţie cu operaţii pe bits 22 Izolarea celor 4 grupuri de 2 bits se face prin aplicarea unui ŞI pe bits cu masca formată din exact 2 bits de 1 plasaţi pe poziţiile 6-7, 4-5, 2-3, respectiv 1-2, aplicată caracterului de lucru a: G1 = a & 0b11000000 G2 = a & 0b00110000 G3 = a & 0b00001100 G4 = a & 0b00000011, după care DEPLASAT-STÂNGA sau DEPLASARE-DREAPTA cu 2 pozitii, pentru a duce acesti bits la noul lor loc: G1 = G1 >> 2 G2 = G2 << 2 G3 = G3 >> 2 G4 = G4 << 2 sau, comprimat: G1 >>= 2 G2 <<= 2 G3 >>= 2 G4 <<= 2, rezultatul procesării fiind expresia: G1 G2 G3 G4, căci poziţiile care erau mascate la identificarea secvenţelor de bits sunt nule şi nu afectează operaţia de SAU pe bits. 20 La fel cum constantele scrise în hexazecimal se pot scrie cu prefixul 0x. 21 Un cast implicit este atunci când avem o operaţie de forma a op b, cu a şi b având tipuri diferite, iar b fiind compatibil cu a, printr+o conversie care nu generează pierderi informaţionale (de exemplu, de la char la int sau de la int la long int). 22 Clasa a X-a. 3
Asambland, algoritmul devine: Citeste n For( i=1; i<=n; i++) Citeste caracter a G1 = a & 0b11000000 G2 = a & 0b00110000 G3 = a & 0b00001100 G4 = a & 0b00000011 G1 = G1 >> 2 G2 = G2 << 2 G3 = G3 >> 2 G4 = G4 << 2 C = G1 G2 G3 G4 Afiseaza caracter C programul C/C++ fiind: #include <iostream> using namespace std; int main() int i, n; char a, c, G1, G2, G3, G4; cin >> n; for (i=1; i<=n; i++) cin >> a; G1 = a & 0b11000000; G2 = a & 0b00110000; G3 = a & 0b00001100; G4 = a & 0b00000011; G1 >>= 2; G2 <<= 2; G3 >>= 2; G4 <<= 2; c = G1 G2 G3 G4; cout << c; Rezultatele de la rulare pentru literele XYZ: 3 XYZ RVZ 4
Process returned 0 (0x0) execution time : 6.500 s Press any key to continue. Cifrele unui număr Pentru un număr întreg: a = a 1 a 2...a n scris în baza 10, obţinerea din acesta a numărului: b = a 1 a 2...a w, unde: w < n scris în baza 10, se poate obţine prin împărţirea întreagă 23 : b = a / 10 n-w, în timp ce obţinerea din acesta a numărului: c = a w+1 a w+2...a n unde: w < n scris în baza 10, se poate obţine prin împărţirea întreagă 24 : c = a % 10 n-w. De asemenea, obţinerea unui nou număr din a, prin adăugarea a w cifre 0 la final se obţine prin înmulţirea întreagă: d = a * 10 w. Aceste reguli se păstrează pentru orice bază b, înlocuind 10 cu baza b. Rezolvare cu cifre în baza 2 25 Aplicând formulele anterioare, numerele obţinute din cele 4 grupe de cifre sunt 26 : 23 Adică câtul împărţirii. 24 Adică restul împărţirii. 25 Clasa a IX-a. 26 Se apkică primele două reguli. 5
G1 = a / 2 6 = a / 64 G2 = a / 2 4 % 2 2 = a / 16 % 4 G3 = a / 2 2 % 2 2 = a / 4 % 4 G4 = a % 2 2 = a % 4, rezultatul fiind obţinut prin combinarea acestora 27 : G2 * 2 6 + G1 * 2 4 + G4 * 2 2 + G3 = G2 * 64 + G1 * 16 + G4 * 4 + G3 Asamblând, algoritmul este: Citeste n For( i=1; i<=n; i++) Citeste caracter a G1 = a / 64 G2 = a / 16 % 4 G3 = a / 4 % 4 G4 = a % 4 C = G2 * 64 + G1 * 16 + G4 * 4 + G3 Afiseaza caracter C iar programul este: #include <iostream> using namespace std; int main() int i, n; char a, c, G1, G2, G3, G4; cin >> n; for (i=1; i<=n; i++) cin >> a; G1 = a / 64; G2 = a / 16 % 4; G3 = a / 4 % 4; G4 = a % 4; c = G2 * 64 + G1 * 16 + G4 * 4 + G3; cout << c; Rezultatul obţinut la rulare, pe aceleaşi date de test este: 3 27 Se aplică a treia regulă. 6
XYZ RVZ Process returned 0 (0x0) execution time : 4.589 s Press any key to continue. Comentarii în baza 4 Grupând câte două cifre binare, putem reformula problema în limbajul bazei 4: 1) două cifre binare înseamnă o cifră în baza 4; 2) aplicând formulele, cele patru cifre sunt: G1 = a / 4 3 = a / 64 G2 = a / 4 2 % 4 1 = a / 16 % 4 G3 = a / 4 1 % 4 1 = a / 4 % 4 G4 = a % 4 1 = a % 4, adică aceleași formule; 3) G1, G2, G3, G4 vor fi cifrele rezultatului final, adică a numărului G2 * 4 3 + G1 * 4 2 + G4 * 4 1 + G3, adică aceași formulă. Referinţe [1] Carmen Popescu, Culegere de probleme de informatică, accesibilă online la adresa https://www.scribd.com/document/282238460/culegere-de-probleme- Informatica-Carmen-Popescu. [2] Proful de Mate, pagina pe Facebook, accesibilă online la adresa https://www.facebook.com/pg/proful-de-info- 1586589874777502/about/?ref=page_internal [3] Marilena Oprea, Radu Marin, Tehnici de optimizare, Editura InfoData, Cluj. Cuprins Enunţul...1 Caracterele ca numere întregi...1 Operaţii pe bits...2 Utilitatea operaţiilor pe bits...2 Constante pe bits...3 O soluţie cu operaţii pe bits...3 Cifrele unui număr...5 Rezolvare cu cifre în baza 2...5 Comentarii în baza 4...7 Referinţe...7 Cuprins...7 Tiberiu Socaciu este licenţiat în informatică şi doctor în cibernetică. Este cadru didactic la CN Petru Rareş din Suceava şi la Universitatea Ştefan cel Mare din Suceava. 7