"Chào, Amigo!"

"Tôi cũng muốn nói về bitmasks và XOR."

"Bạn đã biết rằng các số bao gồm các bit và bạn có thể thực hiện các thao tác khác nhau trên các bit này. Mặt nạ bit là biểu diễn của một số giá trị logic khác nhau (giá trị đúng/sai) dưới dạng một số nguyên. Trong trường hợp này, mỗi giá trị boolean tương ứng với một chút cụ thể. Đây là cách điều này có thể được thực hiện:"

"Biểu diễn nhị phân của lũy thừa hai (1, 2, 4, 8, 16, 32, ...) chỉ liên quan đến việc thiết lập một bit:"

Con số đại diện nhị phân
1 0000 0001
2 0000 0010
4 0000 0100
số 8 0000 1000
16 0001 0000
19 (không phải lũy thừa hai) 0001 0011
31 (không phải lũy thừa hai) 0001 1111

"Vì vậy, bất kỳ số nguyên nào cũng có thể được coi là một mảng các bit hoặc một mảng các giá trị boolean."

"Đây là cách bạn có thể lưu trữ các giá trị boolean khác nhau trong một số:"

giá trị Boolean
boolean a = true;
boolean b = false;
boolean c = true;
boolean d = false;
Các giá trị được đóng gói thành một số:
int result = 0;
 if (a) result += 1; // 1 == 20 — bit 0
 if (b) result += 2; // 2 == 21 — bit 1
 if (c) result += 4; // 4 == 22 — bit 2
 if (d) result += 8; // 8 == 23 — bit 3

"Bây giờ mỗi bit là 1 nếu biến boolean tương ứng là đúng."

Trong trường hợp của chúng tôi, các biến a và c là đúng, vì vậy kết quả bằng 1+4 == 5

0000 0101
0000 dcba

"Tôi nghĩ tôi biết chuyện gì đang xảy ra."

"Hừ, nếu đã hiểu, chúng ta đi tiếp."

"Một int có 32 bit. Một trong số chúng được sử dụng cho ký hiệu của số và 31 bit còn lại có thể được sử dụng để lưu trữ các giá trị của 31 biến boolean."

"A long có 64 bit, nơi chúng tôi có thể lưu trữ 63 biến boolean."

"Chuẩn rồi."

"Hàng chục biến số được nhồi nhét vào một con số. Đó là khá ít."

"Nhưng điều này được áp dụng ở đâu?"

"Chủ yếu trong các tình huống mà bạn cần lưu trữ nhiều thông tin về các đối tượng. Khi bạn lưu trữ nhiều thông tin về một đối tượng, luôn có vài chục biến boolean." Với phương pháp này, tất cả chúng đều được lưu trữ thuận tiện trong một số ."

"Nhấn mạnh vào từ 'được lưu trữ'. Bởi vì thực sự sử dụng số này không thuận tiện cho lắm."

"Nhân tiện, đó chính là điều tôi muốn hỏi. Làm cách nào để trích xuất giá trị boolean từ số?"

"Điều đó không phức tạp chút nào. Giả sử bạn cần xác định xem bit 6 có được đặt thành 1 hay không (2 mũ 5 là 32). Chúng ta có thể kiểm tra như sau:"

Kết hợp các số thành một:
int a = 32; // 25 == 0010 0000
int b = 8; // 23 == 0000 1000
int c = 2; // 21 == 0000 0010

int result = a + b + c; // 32 + 8 + 2 == 42 == 0010 1010
Trích xuất các giá trị bằng cách kiểm tra các bit cụ thể:
int a = result & 32; // 0010 1010 & 0010 0000 = 0010 0000
int b = result & 8; // 0010 1010 & 0000 1000 = 0000 1000
int c = result & 2; // 0010 1010 & 0000 0010 = 0000 0010

"Do đó, làm việc với bitmasks bao gồm ba thao tác:"

1)  Đặt một bit cụ thể thành 0

2)  Đặt một bit cụ thể thành 1

3)  Kiểm tra giá trị của bit cụ thể.

"Lấy bit 6 làm ví dụ."

"Làm thế nào để bạn đặt bit 6 thành 1?"

Mã số Sự miêu tả
result = result | 01000000;
result |= 01000000;
Làm thế nào để bạn đặt bit 6 thành 1?
result = result & 10111111;
result &= 10111111;
Làm thế nào để bạn đặt bit 6 thành 0?
c = result & 01000000;
Làm thế nào để bạn nhận được giá trị của bit 6?

"Điều đó rất bất thường, nhưng không khó. Anh bạn, giờ tôi là một lập trình viên tài ba."

"Và một mẹo nhỏ khác về cách dễ dàng nhận được các số với một bit cụ thể được đặt thành 0 hoặc 1: 01000000 hoặc 10111111."

Đối với điều này, chúng ta có  các toán tử >> và  << .

"1 là lũy thừa 2 mũ 0. Nói cách khác, một số có bit 0 được đặt thành 1. Chúng ta cần một số có bit 6 được đặt."

int c = 1 << 6; // 0000 0001 << 6 == 0100 0000 == 64

"Tuyệt! Điều đó thực sự hữu ích cho những trường hợp như vậy."

"Nhưng nếu tôi cần một số mà mọi bit được đặt thành 1 ngoại trừ một bit cụ thể được đặt thành 0 thì sao?"

"Điều đó cũng không khó:"

int d = ~(1 << 6); // ~0100 0000 == 10111111

"Nói cách khác, tất cả đều rất đơn giản:"

Mã số Sự miêu tả
result = result | (1 << 6);
result |= (1 << 6);
Làm thế nào để bạn đặt bit 6 thành 1?
result = result & ~(1 << 6);
result &= ~(1 << 6);
Làm thế nào để bạn đặt bit 6 thành 0?
c = result & (1 << 6);
Làm thế nào để bạn nhận được giá trị của bit 6?

"Trông cũng không khó lắm. Nhưng tôi sẽ không nhớ ngay được."

"Tuy nhiên, nếu bạn gặp phải một biểu thức đáng sợ chẳng hạn như "kết quả &= ~(1 << 6)" trong mã của người khác, bạn sẽ biết rằng người này chỉ đang làm việc với một bitmask."

"Và nếu bạn gặp nó thường xuyên, thì nó sẽ tự ghi nhớ cho bạn."

"Tự ghi nhớ... Nghe hay đấy. Cảm ơn vì bài học."