1. Dịch chuyển trái theo chiều bit

Java cũng có 3 toán tử dịch chuyển bit : Nếu thực sự cần, bạn có thể rất đơn giản dịch chuyển tất cả các bit của một số sang trái hoặc sang phải một số vị trí.

Để dịch chuyển các bit của một số sang trái, bạn cần toán tử dịch chuyển trái theo từng bit . Đây là cách nó được viết:

a << b

Đâu alà số có các bit đang được dịch chuyển và blà một số cho biết số lần dịch chuyển các bit của số đó asang trái. Trong quá trình hoạt động này, các bit thứ tự thấp được thêm vào bên phải là số không.

Ví dụ:

Ví dụ Kết quả
0b00000011 << 1
0b00000110
0b00000011 << 2
0b00001100
0b00000011 << 5
0b01100000
0b00000011 << 20
0b001100000000000000000000

Dịch chuyển một chữ số sang trái có tác dụng tương tự như nhân một số với 2.

Muốn nhân một số với 16? 16 cũng giống như 2 4 . Vì vậy, bạn di chuyển 4 chữ số sang trái


2. Dịch chuyển bit sang phải

Các bit cũng có thể được chuyển sang bên phải. Để thực hiện việc này, hãy sử dụng toán tử dịch chuyển phải theo bit . Đây là cách nó được viết:

a >> b

Đâu alà số có các bit đang được dịch chuyển và blà số lần dịch chuyển các bit của số đó asang phải.

Ví dụ:

Ví dụ Kết quả
0b11000011 >> 1
0b01100001
0b11000011 >> 2
0b00110000
0b11000011 >> 5
0b00000110
0b11000011 >> 20
0b00000000

Dịch chuyển một chữ số sang phải có tác dụng tương tự như chia một số cho 2.

Trong quá trình hoạt động này, các bit bậc cao được thêm vào bên trái là số không, nhưng không phải lúc nào cũng vậy !

Quan trọng!

Bit ngoài cùng bên trái của một số có dấu được gọi là bit dấu : nếu số đó là số dương thì nó là 0; nhưng nếu số âm, bit này là 1.

Khi dịch chuyển các bit của một số sang phải, giá trị của bit dấu thường cũng sẽ dịch chuyển và dấu của số đó sẽ bị mất. Theo đó, đối với các số âm (trong đó bit ngoài cùng bên trái là 1), bit này được xử lý đặc biệt. Khi dịch chuyển các bit của một số sang bên phải, a 0được thêm vào bên trái nếu bit ngoài cùng bên trái là 0, và a 1được thêm vào bên trái nếu bit ngoài cùng bên trái là 1.

Nhưng trong ví dụ trên, đó dường như không phải là kết quả. Tại sao? Bởi vì số nguyên bằng chữ là ints, và  thực sự có nghĩa là . Nghĩa là, bit ngoài cùng bên trái bằng không.0b111111110b00000000000000000000000011111111

Nhiều lập trình viên thất vọng với hành vi dịch chuyển phải này và muốn số luôn được đệm bằng số không. Vì vậy, Java đã thêm một toán tử dịch chuyển phải khác .

Đây là cách nó được viết:

a >>> b

Đâu a là số có các bit đang được dịch chuyển và b  là số lần dịch chuyển các bit của số đó asang phải. Toán tử này luôn nối các số 0 ở bên trái, bất kể giá trị ban đầu của bit dấu của số đó a.



3. Làm việc với cờ

Các lập trình viên đã tạo ra một lĩnh vực nghiên cứu gần như hoàn toàn mới trên cơ sở hoạt động theo bit và dịch chuyển: làm việc với các cờ.

Khi máy tính có rất ít bộ nhớ, việc nhồi nhét nhiều thông tin vào một con số rất phổ biến. Một số được coi là một mảng bit: int là 32 bit và long là 64 bit.

Bạn có thể viết nhiều thông tin trong một số như vậy, đặc biệt nếu bạn cần lưu trữ các giá trị logic ( truehoặc false). Một đĩa đơn longgiống như một booleanmảng bao gồm 64 phần tử. Các bit này được gọi là cờ và được thao tác bằng các thao tác sau:

  • bộ cờ
    (tạo một bit cụ thể bằng 1)
  • đặt lại cờ
    (tạo một bit cụ thể bằng 0)
  • kiểm tra cờ
    (kiểm tra giá trị của một bit cụ thể)

Và đây là cách nó được thực hiện với toán tử bitwise.

Đặt cờ

Để đặt một bit cụ thể thành 1, bạn cần thực hiện thao tác OR theo bit giữa số có bit mà bạn muốn đặt và một số được tạo đặc biệt, trong đó chỉ có bit đó là 1.

Ví dụ: giả sử bạn có số 0b00001010và bạn cần đặt bit thứ 5 thành 1. Trong trường hợp đó, bạn cần phải:

0b00001010 | 0b00010000 = 0b00011010

Nếu bit thứ 5 đã được đặt thành một, thì sẽ không có gì thay đổi.

Nói chung, thao tác đặt cờ có thể được viết như sau

a | (1 << b)

Đâu a là số có bit sẽ được đặt thành 1. Và b là vị trí của bit được thiết lập. Sử dụng toán tử dịch trái ở đây cực kỳ tiện lợi, vì bạn có thể biết ngay chúng ta đang làm việc với bit nào.

Đặt lại cờ

Để đặt lại một bit cụ thể (nghĩa là đặt thành 0) mà không làm phiền các bit khác, bạn cần thực hiện thao &tác giữa số có bit mà bạn muốn đặt lại (tức là đặt thành 0) và một số được tạo đặc biệt, trong đó tất cả các bit đều bằng 1ngoại trừ cho bit bạn muốn thiết lập lại.

Ví dụ: giả sử bạn có số 0b00001010và bạn cần đặt bit thứ 4 thành 0. Trong trường hợp đó, bạn cần phải:

0b00001010 & 0b11110111 = 0b00000010

Nếu bit thứ 4 đã được đặt thành 0, thì sẽ không có gì thay đổi.

Nói chung, hoạt động đặt lại cờ có thể được viết như sau

a & ~(1 << b)

Đâu a là số có bit sẽ được đặt lại thành 0. Và b là vị trí của bit được xóa.

Để có được một số mà tất cả các bit đều 1ngoại trừ số mà chúng ta muốn bằng 0, trước tiên chúng ta dịch chuyển 1 vị trí b  sang trái, sau đó sử dụng NOTtoán tử theo chiều bit để đảo ngược kết quả.

Kiểm tra cờ

Ngoài việc đặt hoặc đặt lại một cờ cụ thể, đôi khi bạn chỉ cần kiểm tra xem một cờ đã cho có được đặt hay không, tức là liệu một bit nhất định có bằng 1. Điều này khá dễ thực hiện với bitwise &.

Ví dụ: giả sử bạn cần kiểm tra xem bit thứ 4 có được đặt thành 1số hay không 0b00001010. Sau đó, bạn cần phải làm điều này:

if ( (0b00001010 & 0b00001000) == 0b00001000 )

Nói chung, thao tác kiểm tra cờ có thể được viết như sau

(a & (1 << b)) == (1 << b)

Đâu a là số có bit đang được kiểm tra. Và b là vị trí của bit được kiểm tra.


4. Mã hóa

Hoạt động bitwise XORthường được các lập trình viên sử dụng để mã hóa đơn giản. Nói chung, mã hóa như vậy trông như thế này:

result = number ^ password;

number Dữ liệu chúng tôi muốn mã hóa ở đâu , password là một số đặc biệt được sử dụng làm "mật khẩu" cho dữ liệu và result là số được mã hóa.

number == (number ^ password) ^ password;

Điều quan trọng ở đây là khi XORtoán tử được áp dụng cho một số hai lần, nó sẽ tạo ra số ban đầu, bất kể "mật khẩu" là gì.

Để khôi phục number từ encrypted result, bạn chỉ cần thực hiện lại thao tác:

original number = result ^ password;

Ví dụ:

class Solution
{
   public static int[] encrypt(int[] data, int password)
   {
     int[] result = new int[data.length];
     for (int i = 0; i <  data.length; i++)
       result[i] = data[i] ^ password;
     return result;
   }

   public static void main(String[] args)
   {
     int[] data =  {1, 3, 5, 7, 9, 11};
     int password = 199;

     // Encrypt the array of data
     int[] encrypted = encrypt(data, password);
     System.out.println(Arrays.toString(encrypted));

     // Decrypt the array of data
     int[] decrypted = encrypt(encrypted, password);
     System.out.println(Arrays.toString(decrypted));
   }
}