Sunteți pe pagina 1din 10

Programarea calculatoarelor și limbaje de programare (2020/2021)

Lucrarea de laborator 4 - suport

Operatori pe biți în C/C++

Operatori pe biți în C/C++.

Operatorii pe biți se aplică numai datelor de tip întreg și presupun manipularea


directă a biților din reprezentarea în memorie a operanzilor. Ei se aplica fiecărui bit din
reprezentarea în memorie a operanzilor. În ordinea descrescătoare a priorității, operatorii
pe biți sunt:

~ complementare

<< deplasare la stânga (left shift), >> deplasare la dreapta (right shift)

& și (conjuncție)

^ sau exclusiv

| sau (disjuncție)
Operatorul ~ transforma fiecare bit din reprezentarea operandului în
complementarul său, adică biții 1 în 0 și biții 0 în 1:
b ~b
0 1
1 0

Operatorii &, ^, | realizează operațiile corespunzătoare între toate perechile de biți


de pe poziții identice în reprezentările în memorie ale operanzilor. Dacă b1 și b2 reprezintă
o astfel de pereche, în tabelul următor sunt indicate valorile obținute prin aplicarea
operatorilor: &, ^, |.
b1 b2 b1 & b2 b1^ b2 b1 | b2
0 0 0 0 0
0 1 0 1 1
1 0 0 1 1
1 1 1 0 1

Exemplu:
0…0 1111 1111 1010 0001 &
0…0 1110 0010 0001 0011
--------------------------------
0…0 1110 0010 0000 0001
e 2 0 1

0…0 1111 1111 1010 0001 ^


0…0 1110 0010 0001 0011
---------------------------------
0…0 0001 1101 1011 0010
1 d b 2

0…0 1111 1111 1010 0001 |


0…0 1110 0010 0001 0011
--------------------------------
0…0 1111 1111 1011 0011
f f b 3

~ 0….0 1111 1111 1010 0001 =


1…1 0000 0000 0101 1110
f ... f 0 0 5 e
x = 0b1111111110100001= 0xffa1, y =0b1110001000010011= 0xe213

Programul de mai jos testează rezultatele obținute mai sus:


#include <iostream>
int main() {
unsigned int x = 0xffa1, y = 0xe213;
std::cout << std::hex << std::showbase;
std::cout << x << " & " << y
<< " = " << (x & y) << std::endl;
std::cout << x << " ^ " << y
<< " = " << (x ^ y) << std::endl;
std::cout << x << " | " << y
<< " = " << (x | y) << std::endl;
std::cout << "~ " << x << " = " << (~x) << std::endl;
std::cout << "~ " << y << " = " << (~y) << std::endl;

return 0;
}
Programul afișează
0xffa1 & 0xe213 = 0xe201
0xffa1 ^ 0xe213 = 0x1db2
0xffa1 | 0xe213 = 0xffb3
~ 0xffa1 = 0xffff005e
~ 0xe213 = 0xffff1dec

Operatorul de deplasare la stânga (left shift) << este un operator binar care are ca
rezultat numărul obținut prin deplasare spre stânga a biților din reprezentarea în memorie
a primului operand cu un număr de poziții egal cu al doilea operand.
Operatorul de deplasare la dreapta (right shift) >> este un operator binar care are ca
rezultat numărul obținut prin deplasare spre dreapta a biților din reprezentarea în memorie
a primului operand cu un număr de poziții egal cu al doilea operand.
Deci operatorii de deplasare sunt binari, primul operand este cel ai cărui biți sunt
deplasați, iar al doilea indică numărul de biți cu care se face deplasarea.
a << n
a >> n
La deplasarea la stânga cu o poziție, bitul cel mai semnificativ se pierde, iar in dreapta se
completează cu bitul 0. La deplasarea la dreapta cu o poziție, bitul cel mai puțin
semnificativ se pierde, iar în stânga se completează cu 0 (pentru operanzi fără semn sau cu
semn nenegativi). În cazul în care operandul din stânga este negativ, completarea bitului
din stânga (cel mai semnificativ) depinde de implementare (de obicei se adaugă un bit
identic cu cel de semn).
Pentru operanzi fără semn sau cu semn nenegativi, cu excepția cazurilor când se
produce depășire, deplasarea la stânga cu n biți echivalează cu înmulțirea cu 2n.
Deplasarea la dreapta cu n biți echivalează cu împărțirea la 2n.
Începând cu standardul C++20, valoarea expresiei a << n este egală cu a*2n modulo
2N, unde N este numărul de biți asociat tipului rezultatului. Valoarea expresiei a >> n este
partea întreagă a a/2n.
Dacă valoarea operandului drept este negativă sau este mai mare sau egală cu
numărul de biți din operandul stâng (promovat), comportamentul operatorilor de deplasare
este nedefinit.

Probleme rezolvate

Pb2. Se dă o mască pe 8 biți: 11110001. Pentru un număr întreg fără semn pe 16


biți introdus de la tastatură se cere să se afișeze cele trei numere obținute prin:
- marcarea cu 1 a biților corespunzători biților 1 din mască,
- marcarea cu 0 a biților corespunzători biților 1 din mască,
- selectarea biților corespunzători biților 1 din mască.

#include <iostream>
#include <cstdint>

int main () {
uint8_t masca = 0xf1; //masca = 0b11110001
uint16_t x;
std::cout << std::hex << std::showbase;
std::cout << (unsigned) masca << std::endl;
std::cin.unsetf (std::ios::dec);
std::cin.unsetf (std::ios::hex);
std::cin.unsetf (std::ios::oct);
std::cout << "x = ";
std::cin >> x;
std::cout << "marcarea cu 1 a bitilor: " << (x | masca) << '\n'
<< "marcarea cu 0 a bitilor: " << (x & ~masca) << '\n'
<< "Selectarea bitilor: " << (x & masca) << std::endl;
return 0;
}

În programul anterior am folosit


std::cin.unsetf(std::ios::dec);
std::cin.unsetf(std::ios::hex);
std::cin.unsetf(std::ios::oct);
pentru a permite interpretare constantelor întregi ca fiind reprezentate în baza 10, 16
(0x… ) sau 8 (0…) în funcție de forma lor. Se poate folosi echivalent:
std::cin.unsetf(std::ios::basefield);

Pb 3. Să se afișeze reprezentarea binară a unui număr întreg introdus de la


tastatură.
x = 0b101101
masca = 1 << p => 1000… 0000 (p = numărul de biți din reprezentarea lui x - 1)
x & masca
masca >> 1 => 010….0
….

#include <iostream>
#include <climits>
int main() {
long long int x;
unsigned long long int ux, masca = 0;
std::cin.unsetf(std::ios::dec);
std::cin.unsetf(std::ios::hex);
std::cin.unsetf(std::ios::oct);
std::cout << "x = ";
std::cin >> x;
if(x == 0){
std::cout << '0';
}
else {
if (x < 0) {
ux = (unsigned long long int) (- x);
std::cout << '-';
}
else {
ux= (unsigned long long int) x;
}
masca = 1ull << (sizeof(ux)*CHAR_BIT - 1 );
while ((ux & masca) == 0) {
masca >>= 1;
}
while (masca) {
if (ux & masca) {
std::cout << '1';
}
else {
std::cout << '0';
}
masca >>= 1;
}
}
std::cout << std::endl;
return 0;
}

Pb 4. Să se determine un număr întreg fără semn a cărui reprezentare binară are


biții corespunzători puterilor lui 2 de la p la q egali cu 1 și în rest 0.
Indicație: (1ull << p) – 1 este
00…010…0 - 1+1 =10
1
---------------
00 … 01…11

#include <iostream>
int main() {
unsigned long long int x;
unsigned int p, q, vaux;
std::cout << "p = "; std::cin >> p;
std::cout << "q = "; std::cin >> q;
if (p > q) {
vaux = p;
p = q;
q = vaux;
}
x = ((1ull << p) - 1) ^ ((1ull << q+1) - 1);
std::cout << std::hex << std::showbase << x << std:: endl;
return 0;
}
Variantă cu reprezentare binară

#include <iostream>
#include <climits>

int main() {
unsigned long long int x, masca = 0;
unsigned int p, q, vaux;
std::cout << "p = "; std::cin >> p;
std::cout << "q = "; std::cin >> q;
if (p > q) {
vaux = p;
p = q;
q = vaux;
}
x = ((1ull << p) - 1) ^ ((1ull << q+1) - 1);
std::cout << std::hex << std::showbase << x << std:: endl;
if(x == 0){
std::cout << '0';
}
else {
masca = 1ull << (sizeof(x)*CHAR_BIT - 1 );
while ((x & masca) == 0) {
masca >>= 1;
}
while (masca) {
if (x & masca) {
std::cout << '1';
}
else {
std::cout << '0';
}
masca >>= 1;
}
}
std::cout << std::endl;
return 0;
}

Pb 5. Se dă un tablou cu elemente întregi în care fiecare valoare apare de un număr


par de ori cu excepția a două dintre ele. Să se determine valorile respective.
x^y=y^x
(x ^ y) ^ z = x ^ (y ^ z)
0^x=x
x^x=0

#include <iostream>
int main() {
int x[] = {1, 2, 1, 3, 4, 4, 2, 5}, n = 8, i, xor_x, xor_x1, xor_x2, bit_test;
xor_x = x[0];
for(i = 1; i < n; ++i) {
xor_x ^= x[i];
}
bit_test = xor_x & ~(xor_x - 1);
xor_x1 = 0;
xor_x2 = 0;
for(i = 0; i < n; ++i){
if(x[i] & bit_test) {
xor_x1 ^= x[i];
}
else {
xor_x2 ^= x[i];
}
}
std::cout<<xor_x1<<' '<<xor_x2<<std::endl;
return 0;
}

Probleme propuse
1. Se dau două numere întregi fără semn n și k. Să se determine câtul (întreg) și restul
împărțirii lui n la 2k.
2. Se dă un număr întreg fără semn n. Să se verifice dacă n este o putere a lui 2.
3. Să se determine cel mai mare număr întreg k cu proprietatea că 2k divide un număr
întreg fără semn n dat.
4. Se dă un tablou cu elemente întregi în care fiecare valoare apare de un număr par
de ori cu excepția uneia. Să se determine valoarea respectivă
5. (Temă minimală). Se dă un număr întreg fără semn n. Să se determine numărul
întreg fără semn a cărui reprezentare binară coincide cu secvența de cifre din
reprezentarea binară a numărului n de la bitul p (corespunzător puterii 2p) până la
bitul q (corespunzător puterii 2q), cu p și q date.

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