Thao tác với bit

Các phép toán với bit

Một số nguyên có thể biểu diễn bằng nhiều cách: sử dụng hệ nhị phân, hệ bát phân hoặc thập lục phân (hexa).

Ví dụ số 21 (thập phân) có thể biểu diễn trong hệ hexa là 15, hệ bát phân là 25 và nhị phân là 10101. Cách viết trong C như sau 0x15 hoặc 0X15 (hexa), 025 (bát phân) và 0b10101 (nhị phân).

Các phép toán với bit gồm có:

Toán tử Giải thích
& AND bit
| OR bit
^ XOR bit
~ NOT bit
<< SHIFT LEFT, dịch trái bit
>> SHIFT RIGHT, dịch phải bit

Phép NOT bit là phép đảo bit, sẽ trả về bit 0 khi bit đầu vào là 1 (và ngược lại). Phép toán AND, OR bit tương tự như phép toán logic, phép toán XOR bit sẽ trả về bit 0 khi hai bit đầu vào là giống nhau, trả về 1 khi hai bit đầu vào là khác nhau. Cụ thể như sau:

Bit 1 Bit 2 AND OR XOR
1 1 1 1 0
0 0 0 0 0
1 0 0 1 1
0 1 0 1 1

Ví dụ

1
2
3
4
5
6
7
8
9
int a = 21 & 13; // 0b10101 & 0b01101 -> 0b00101
int b = 21 | 13; // 0b10101 | 0b01101 -> 0b11101
int c = 21 ^ 13; // 0b10101 ^ 0b01101 -> 0b11000
char d = ~21; // Kết quả là -22, sẽ được giải thích ở dưới
unsigned char e = ~21; // Kết quả là 234

// dịch trái và dịch phải bit
int a = 0b10101 << 2; // dịch 2 bit trái -> 0b1010100;
int b = 0b10101 >> 2; // dịch 2 bit phải -> 0b101;

Tính chất của phép toán trên bit

  • Toán tử &, |^ có tính chất giao hoán. Ví dụ a & bb & a luôn ra kết quả giống nhau.
  • a & 0 = 0, a | 0 = aa ^ 0 = a
  • a & a = aa | a = a
  • a ^ a = 0
  • Nếu a ^ b = c thì a ^ c = bb ^ c = a
  • Phép toán dịch n bit trái tương đương với nhân với 2n
  • Phép toán dịch n bit phải tương đương với chia cho 2n

Kiến thức nâng cao với bit

Biểu diễn số âm

Để đơn giản thì chúng ta xét trường hợp với kiểu char chỉ có 8 bit biểu diễn các số từ -128 đến 127. Câu hỏi đầu tiên là số -1 được biểu diễn như thế nào. Rất đơn giản, ta có -1 + 1 = 0, số 1 được biểu diễn trong hệ nhị phân là 00000001 nên số -1 sẽ là 11111111. Vì 00000001 + 11111111 = 00000000 (bit tràn quá 8 bit sẽ được bỏ qua). Phương pháp biểu diễn số âm kiểu này được gọi là lấy số bù 2.

Bảng sau liệt kê các số âm từ -1 đến -5 (các số nhị phân được phân cách bằng _ cho dễ nhìn).

Số dương Số dương nhị phân Số âm Số âm nhị phân Tổng nhị phân
1 0000_0001 -1 1111_1111 0
2 0000_0010 -2 1111_1110 0
3 0000_0011 -3 1111_1101 0
4 0000_0100 -4 1111_1100 0
5 0000_0101 -5 1111_1011 0
127 0111_1111 -127 1000_0001 0

Số -128 sẽ được biểu diễn là 1000_0000. Để ý là bit đầu tiên của tám bit này nếu là số 1 thì sẽ là số âm, ngược lại sẽ là số dương.

Lấy phép NOT bit

Để ý khi đảo các bit của số 1 (nhị phân là 0000_0001) thì được các bit 1111_1110 ứng với số -2. Tương tự với các số khác. Sau đây là bảng NOT bit (phép toán ~) các số từ 0 đến 4 với kiểu dữ liệu char:

Số thập phân Số nhị phân NOT bit nhị phân NOT bit thập phân
0 0000_0000 1111_1111 -1
1 0000_0001 1111_1110 -2
2 0000_0010 1111_1101 -3
3 0000_0011 1111_1100 -4
4 0000_0100 1111_1011 -5

Công thức của chúng ta sẽ là ~a = -a - 1. Vậy nên kết quả của ví dụ ở trên ~21 sẽ là -22.

Lấy NOT bit với số nguyên không dấu

Với kiểu dữ liệu là số nguyên không dấu, cách thực hiện ở dạng nhị phân sẽ tương tự như trên, tuy nhiên hiển thị ở hệ thập phân lại khác.

Kiểu unsigned char sẽ nhận các giá trị từ 0 đến 255. Sau đây là bảng NOT bit các số từ 0 đến 4:

Số thập phân Số nhị phân NOT bit nhị phân NOT bit thập phân
0 0000_0000 1111_1111 255
1 0000_0001 1111_1110 254
2 0000_0010 1111_1101 253
3 0000_0011 1111_1100 252
4 0000_0100 1111_1011 251

Công thức cho trường hợp số nguyên không dấu sẽ là ~a = 255 - a (với 255 là giá trị lớn nhất của kiểu char).