Các toán tử Bitwise

1- Bitwise

Trong lập trình máy tính kỹ thuật số. Phép toán bitwise hoạt động trên một hoặc nhiều số nhị phân (binary numerals), hoặc các chuỗi giống số nhị phân. Đây là một phép toán đơn giản và nhanh, được hỗ trợ trực tiếp bởi bộ xử lý (processor). Thông thường các phép tính bitwise nhanh hơn rất nhiều so với phép nhân, phép chia, đôi khi nhanh hơn đáng kể so với phép cộng. Các phép tính bitwise sử dụng ít năng lượng hơn bởi nó ít sử dụng tài nguyên.
Có 7 phép toán bitwise:
Operator Name Description
& AND Nếu cả 2 bit là 1, giá trị trả về là 1, ngược lại trả về 0.
| OR Nếu một trong hai bit là 1, giá trị trả về là 1, ngược lại trả về 0.
^ XOR Nếu hai bit khác nhau, giá trị trả về là 1, ngược lại trả về 0.
~ NOT Đảo ngược tất cả các bit, 0 thành 1 và 1 thành 0.
<< Zero fill left shift Dịch chuyển tất cả các bit sang bên trái.
>> Signed right shift Dịch chuyển tất cả các bit sang bên phải ngoại trừ bit đầu tiên.
>>> Zero fill right shift Dịch chuyển tất cả các bit sang bên phải.

Bitwise AND

Khi một bitwise AND được thực hiện trên một cặp bit, nó trả về 1 nếu cả 2 bit là 1, ngược lại trả về 0.
Ví dụ với 1 bit:
Operation Result
0 & 0 0
0 & 1 0
1 & 0 0
1 & 1 1
Ví dụ với 4 bit:
Operation Result
1111 & 0000 0000
1111 & 0001 0001
1111 & 0010 0010
1111 & 0100 0100

Bitwise OR:

Khi một bitwise OR được thực hiện trên một cặp bit, nó trả về 1 nếu một trong các bit là 1, ngược lại trả về 0.
Ví dụ với 1 bit:
Operation Result
0 | 0 0
0 | 1
1 | 0 1
1 | 1 1
Ví dụ với 4 bit:
Operation Result
1111 | 0000 1111
1111 | 0001 1111
1111 | 0010 1111
1111 | 0100 1111

Bitwise XOR

Khi một bitwise XOR được thực hiện trên một cặp bit, nó trả về 1 nếu các bit khác nhau, ngược lại trả về 0.
Ví dụ với 1 bit:
Operation Result
0 ^ 0 0
0 ^ 1
1 ^ 0 1
1 ^ 1
Ví dụ với 4 bit:
Operation Result
1111 ^ 0000 1111
1111 ^ 0001 1110
1111 ^ 0010 1101
1111 ^ 0100 1011

Bitwise NOT

Khi một Bitwise NOT được sử dụng nó sẽ đảo ngược tất cả các bit. 1 thành 0, và 0 thành 1.
Ví dụ với 1 bit:
Operation Result
~ 0 1
~ 1 0
Ví dụ với 4 bit:
Operation Result
~ 0000 1111
~ 0001 0001
~ 0010 1101
~ 1100 0011

2- Phép toán Bitwise trên các số

Các ngôn ngữ khác nhau có thể có nhiều kiểu dữ liệu để biểu diễn số.
  • Java: byte, short, int, long, double.
  • C#: byte, sbyte, short, ushort, int, uint, long, ulong, float, double
  • Javascript: double
  • .....
Javascript lưu trữ các số như là các số chấm động 64 bit (64 bits floating point numbers). Nhưng các phép toán bitwise được thực hiện trên các số nguyên 32 bit. Các ngôn ngữ khác như Java, C#,.. các phép toán bitwise cũng được thực hiện trên các số nguyên 32 bit.
Vì vậy trước khi thực hiện phép toán bitwise với các số bạn phải chuyển đổi mỗi số thành một dẫy 32 số nhị phân.
Base 10 Base 2 32 bits
5 101 00000000000000000000000000000101
218 11011010 00000000000000000000000011011010
Trong Javascript phương thức toString(base) giúp bạn chuyển một số bất kỳ từ hệ cơ số 10 (base 10) sang hệ cơ số khác.
toString-base-example.js (Javascript)
let a = 8;


// Base 2 string.
console.log( a.toString(2) );// 1000

// Base 8 string
console.log( a.toString(8) ); // 10

// Base 16 string
console.log( a.toString(16) ); // 8


let b = 218;


// Base 2 string.
console.log( b.toString(2) );// 11011010

// Base 8 string
console.log( b.toString(8) ); // 332

// Base 16 string
console.log( b.toString(16) ); // da

 
Ví dụ:
Decimal Binary
5 00000000000000000000000000000101
1 00000000000000000000000000000001
5 & 1 = 1 00000000000000000000000000000001
5 | 1  = 5 00000000000000000000000000000101
5 ^ 1  = 4 00000000000000000000000000000100
~ 5    = -6 11111111111111111111111111111010
Chú ý: Trong 32 bit, bit đầu tiên được sử dụng để xác định dấu (sign) của số, nếu bit này là 1 tương ứng với dấu trừ ( - ), nếu bit này là 0 tương ứng với dấu cộng ( + )

Bitwise Left Shift (<<)

Decimal Binary
5 00000000000000000000000000000101
5 << 1  = 10 00000000000000000000000000001010
5 << 2  = 20 00000000000000000000000000010100
Toán tử Bitwise Left Shift ( << ) có thể làm thay đổi dấu (sign) của số.
(Javascript code)
console.log( 1073741824 << 1); // -2147483648

console.log( 2684354560 << 1); // 1073741824

Bitwise Right Shift (>>)  [Unsigned Right Shift]

Decimal Binary
29 00000000000000000000000000011101
29 >> 1  = 14 00000000000000000000000000001110
29 >> 2  = 7 00000000000000000000000000000111
Toán tử Bitwise Right Shift ( >> ) không làm thay đổi dấu của số, vì bit đầu tiên không bị di chuyển.

Bitwise Right Shift (>>>) [Zero fill right Shift]

Toán tử Bitwise Right Shift ( >>> ) có thể làm thay đổi dấu của số.
(Javascript Code)
console.log( -1073741824 >>> 1); // 1610612736

console.log( 1073741824 >>> 1); // 536870912

3- Bitwise để làm gì?

Các phép tính bitwise được hỗ trợ trực tiếp bởi bộ xử lý (processor) của máy tính nên nó thực hiện rất nhanh. Dưới đây tôi liệt kê một vài ví dụ sử dụng các phép toán này.
Sử dụng các phép toán bitwise trên các String (characters) trên các ngôn ngữ Java, C#, C/C++ ... Chú ý: một vài ngôn ngữ như Javascript không hỗ trợ phép toán bitwise với kiểu String.
Chuyển đổi một chữ hoa (Uppercase) sang chữ thường (Lowercase):
// Rule: x | ' '

('A' | ' ') ==> 'a'
('B' | ' ') ==> 'b'

('a' | ' ') => 'a'
Chuyển đổi chữ thường (Lowercase) sang chữ hoa (Uppercase):
// Rule: x & '_'


('a' & '_') ==> 'A'
('b' & '_') ==> 'B'

('A' & '_') ==> 'A'
Đảo ngược chữ hoa thành chữ thường, chữ thường thành chữ hoa:
// Rule: x ^ ' '
 
('a' ^ ' ') ==> 'A'
('A' ^ ' ') ==> 'a'
Xem vị trí các chữ cái Latin (Chỉ áp dụng cho chữ hoa)
// Rule:  x & '?'

'A' & '?'  ==> 1
'B' & '?'  ==> 2
...
'Z' & '?'  ==> 26

// Rule:  x ^ '@'


'A' ^ '@'  ==> 1
'B' ^ '@'  ==> 2
...
'Z' ^ '@'  ==> 26


 
Xem vị trí các chữ cái Latin (Chỉ áp dụng cho chữ thường)
 
// Rule:  x ^ '`'


'a' ^ '`'  ==> 1
'b' ^ '`'  ==> 2
...
'z' ^ '`'  ==> 26

// '`' : binary ( 1100000 ), hex('60'),  chr(96)
Xem vị trí các chữ cái Latin, áp dụng cho cả chữ hoa và chữ thường:
// Rule:  x & '\u001F'

'A' & '\u001F'  ==> 1
'B' & '\u001F'  ==> 2
...
'Z' & '\u001F'  ==> 26

'A' & '\u001F'  ==> 1
'B' & '\u001F'  ==> 2
...
'Z' & '\u001F'  ==> 26