Bài 4 · Vận dụng · 20 phút· Cập nhật 11/06/2026
Phép toán trên bit (bitwise)
Biên soạn bởi Nguyễn Anh Tuấn
AND/OR/XOR/NOT & dịch bit trên cả byte; mẹo chẵn/lẻ bằng & 1; cờ & mặt nạ; vì sao một phép bitwise = một lệnh ALU qua cổng logic.
Ở bài Hệ nhị phân ta thấy mỗi số là một dãy bit (0/1). Ở bài Cổng logic ta thấy AND/OR/XOR/NOT làm việc trên từng bit. Phép toán trên bit (bitwise) ghép hai điều đó: tác động lên từng bit của cả con số cùng lúc - không phải tính theo giá trị thập phân.
- ▸Phép số học (+, ×, %) làm việc trên GIÁ TRỊ; bitwise làm việc trên từng BIT.
- ▸Sáu phép thường gặp: AND (&), OR (|), XOR (^), NOT (~), dịch trái («), dịch phải (»).
- ▸Trong code thật, dịch bit viết là << và >> (C, Python, JavaScript…) - bài này dùng « » cho dễ nhìn.
Mỗi phép áp đúng bảng chân trị của cổng logic, nhưng cho cả 8 cột bit một lượt. Thử bật-tắt từng bit và đổi phép:
Bấm ô bit của A/ B để bật–tắt. Kết quả AND = 32 (hex 0x20). Bit cuối của A là 0 → A là số chẵn (chính là A & 1).
AND giữ bit chung; OR gộp; XOR = khác nhau; NOT lật
1011 0010 A = 178
& 0110 1100 B = 108
---------
0010 0000 = 32 AND: ra 1 chi khi CA HAI bit la 1
1011 0010
| 0110 1100
---------
1111 1110 = 254 OR: ra 1 neu CO IT NHAT MOT bit 1
1011 0010
^ 0110 1100
---------
1101 1110 = 222 XOR: ra 1 khi HAI bit KHAC nhau
~ 1011 0010 = 0100 1101 = 77 NOT: lat tung bit (trong 8-bit) - ▸AND (&): lọc/giữ bit - “mặt nạ”. OR (|): bật bit. XOR (^): đảo bit có chọn lọc.
- ▸NOT (~) lật mọi bit; kết quả phụ thuộc bề rộng (8-bit → ~178 = 77, không phải -179).
- ▸Mỗi phép xử lý 8 bit độc lập, song song.
Dịch trái « đẩy mọi bit sang trái (thêm 0 ở cuối) = nhân với 2ⁿ. Dịch phải » đẩy sang phải = chia cho 2ⁿ (làm tròn xuống). Hệt như thêm/bớt số 0 ở hệ thập phân là nhân/chia 10.
dịch bit
0000 0101 = 5
5 « 3 →
0010 1000 = 40 (= 5 x 8 = 5 x 2^3) dich trai 3 bit
1100 1000 = 200
200 » 2 →
0011 0010 = 50 (= 200 / 4 = 200 / 2^2) dich phai 2 bit Dịch quá tay thì tràn
Bit cuối (phải nhất) mang giá trị 2⁰ = 1 - phần lẻ duy nhất của số; mọi bit khác đều là bội của 2 (luôn chẵn). Nên n & 1 (giữ đúng bit cuối) cho biết ngay: 1 → lẻ, 0 → chẵn.
bit cuối quyết định chẵn/lẻ
1011 0010 & 1 = 0 -> 178 chan
1011 0011 & 1 = 1 -> 179 le
# n & 1 cho ket qua y het n % 2 Trung thực: “% 2 chậm hơn & 1” là chuyện hoang đường
Một số nguyên là một dãy công tắc on/off. Thay vì 8 biến boolean, gói tất cả vào một byte rồi dùng bitwise để bật/tắt/kiểm từng cái - gọn và nhanh. Đây mới là nơi bitwise phát huy hết tác dụng.
quyền truy cập kiểu chmod
READ = 0b001 # 1
WRITE = 0b010 # 2
EXEC = 0b100 # 4
quyen = READ | WRITE # 0b011 -> bat READ va WRITE
co_write = quyen & WRITE # khac 0 -> CO quyen ghi
quyen = quyen & ~WRITE # 0b001 -> TAT WRITE (mat na dao)
quyen = quyen ^ EXEC # 0b101 -> DAO (toggle) EXEC - ▸Bật cờ: giá_trị | mask. Tắt cờ: giá_trị & ~mask.
- ▸Kiểm cờ: (giá_trị & mask) khác 0. Đảo cờ: giá_trị ^ mask.
- ▸Một số = nhiều boolean: quyền tệp (rwx), cờ tính năng, kênh màu R/G/B, mặt nạ mạng…
Mỗi phép bitwise là MỘT lệnh ALU - và ALU chính là dãy cổng AND/OR/XOR/NOT bạn đã ráp ở bài Cổng logic. Làm A & B trên 8 (hay 32, 64) bit chỉ là một lượt tín hiệu chạy qua dãy cổng đó - không vòng lặp, không phép chia nhiều bước. Đó là nghĩa thật của “chạm thẳng vào transistor”: bạn ra lệnh đúng thứ phần cứng làm tự nhiên nhất.
- ▸Bitwise = một lệnh ALU = một lượt qua cổng logic (cực nhanh, cố định).
- ▸“Nhanh” theo nghĩa: làm đúng việc phần cứng sinh ra để làm - không phải mẹo qua mặt % 2.
- ▸Hiểu bit giúp đọc cờ, mặt nạ, giao thức, định dạng tệp… ở mức gần phần cứng.
Tiếp theo
Câu hỏi thường gặp
Trên hệ thống hiện đại: KHÔNG đáng kể. Trình biên dịch tự đổi n % 2 → n & 1, x × 2ⁿ → x « n, và x ÷ 2ⁿ (số không dấu) → x » n. Nên n % 2 == 0 và (n & 1) == 0 ra cùng một lệnh máy, cùng tốc độ. Trong Python (thông dịch) cả hai đều bị chi phí thông dịch lấn át. Bitwise đáng dùng vì CỜ/MẶT NẠ, gói dữ liệu, và để hiểu phần cứng - không phải để "qua mặt" %.
Vì ta làm trên 8-bit. ~0 trên số nguyên đầy đủ là -1 (bù hai, toàn bit 1), nhưng giới hạn 8 bit thì "toàn bit 1" = 1111 1111 = 255. Số bit của kiểu dữ liệu quyết định kết quả NOT.
Có. Bit bị đẩy ra ngoài bề rộng (8 bit) sẽ bị bỏ. Ví dụ 1100 0000 « 1 = 1 1000 0000 → cắt còn 1000 0000 (bit cao biến mất). Đó là tràn - giống giới hạn 8-bit của thanh ghi A ở mô hình CPU.
Tick những điều em tự tin làm được. Càng lên cao, em càng hiểu sâu.
Trả lời vài câu để chắc rằng em đã nắm bài.
Điểm khác biệt cốt lõi giữa phép toán trên bit (bitwise) và phép số học là gì?
- 1
Đọc kết quả bằng tay
Với
A = 1011 0010,B = 0110 1100: tínhA & B,A | B,A ^ B, và~A(8-bit). Đối chiếu với công cụ ở Bước 2.Hoàn thành khi:
A&B = 0010 0000;A|B = 1111 1110;A^B = 1101 1110;~A = 0100 1101. Khớp công cụ. - 2
Dịch = nhân/chia
Tính
5 « 3và200 » 2bằng tay; so với 5 × 8 và 200 ÷ 4.Hoàn thành khi:
5 « 3= 40 = 5×8;200 » 2= 50 = 200÷4. Dịch trái nhân, dịch phải chia (luỹ thừa 2). - 3
Chẵn/lẻ bằng bit
Bằng lời: vì sao chỉ cần nhìn BIT CUỐI là biết một số chẵn hay lẻ? Vì sao
n & 1cho cùng kết quả vớin % 2?Hoàn thành khi: Bit cuối là giá trị 2⁰ = 1 - phần lẻ duy nhất; mọi bit khác là bội của 2 (chẵn).
& 1giữ đúng bit đó = số dư khi chia 2. - 4
Mặt nạ quyền
Đặt
READ=1,WRITE=2,EXEC=4. Choquyen = READ | WRITE. Kiểm “có WRITE?” bằng&. Bỏ WRITE bằng& ~. Bật EXEC bằng|.Hoàn thành khi:
quyen = 011;quyen & WRITE≠ 0 (có);quyen & ~WRITE = 001;quyen | EXEC = 101. - 5
Tràn khi dịch
Trên 8-bit:
1100 0000 « 1ra bao nhiêu? Bit nào bị mất?Hoàn thành khi:
1000 0000(128). Bit 1 ở vị trí 2⁷ bị đẩy ra ngoài 8 bit → mất. - 6
Trung thực về tốc độ
Bằng lời: vì sao câu “
n % 2chậm hơnn & 1” là SAI trên trình biên dịch hiện đại?Hoàn thành khi: Compiler tự đổi
%(và ×/÷) theo luỹ thừa 2 thành phép bit/dịch tương ứng → cùng một lệnh máy, cùng tốc độ.