JavaRush /Blog Java /Random-VI /Hoạt động bitwise trong Java

Hoạt động bitwise trong Java

Xuất bản trong nhóm
Chắc hẳn bạn đã quen với từ “beat”. Nếu chưa thì hãy cùng tìm hiểu nhé :) Bit là đơn vị đo lường thông tin tối thiểu trong máy tính. Tên của nó xuất phát từ tiếng Anh “ chữ số nhị phân ” - “số nhị phân”. Một bit có thể được biểu diễn dưới dạng một trong hai số: 1 hoặc 0. Có một hệ thống số đặc biệt dựa trên số 1 và số 0 - hệ nhị phân. Chúng ta sẽ không đi sâu vào vấn đề toán học mà chỉ lưu ý rằng bất kỳ số nào trong Java đều có thể được chuyển đổi sang dạng nhị phân. Để làm điều này bạn cần sử dụng các lớp bao bọc. Hoạt động theo bit - 1Ví dụ: đây là cách thực hiện với một số int:
public class Main {

   public static void main(String[] args) {

       int x = 342;
       System.out.println(Integer.toBinaryString(x));
   }
}
Đầu ra của bảng điều khiển:

101010110
1010 10110 (tôi đã thêm khoảng trắng để dễ đọc) là số 342 ở dạng nhị phân. Trên thực tế, chúng tôi đã chia số này thành các bit riêng lẻ - số không và số một. Với chúng, chúng ta có thể thực hiện các thao tác được gọi là bitwise.
  • ~- toán tử “KHÔNG” theo bit.

Nó hoạt động rất đơn giản: nó đi qua từng bit của số của chúng ta và thay đổi giá trị của nó thành giá trị ngược lại: số 0 thành số 1, số 1 thành số 0. Nếu chúng ta áp dụng nó cho số 342 thì đây là những gì chúng ta nhận được: 101010110 - số 342 ở dạng nhị phân 010101001 - kết quả của biểu thức ~342 Nhưng vì một biến int có 4 byte, tức là. Trên thực tế, 32 bit, số trong biến được lưu trữ dưới dạng: 00000000 00000000 00000001 01010110- số 342 trong một biến kiểu int trong java 11111111 11111111 11111110 10101001- kết quả của biểu thức ~342 trong java Chúng ta hãy thử thực hiện điều này trong thực tế:
public class Main {

   public static void main(String[] args) {

       int x = 342;
       System.out.println(Integer.toBinaryString(~x));
   }
}
Đầu ra của bảng điều khiển:
11111111111111111111111010101001
  • &— toán tử bitwise “AND”

Như bạn có thể thấy, nó được viết khá giống với logic “AND” ( &&). Toán tử &&, như bạn nhớ, truechỉ trả về nếu cả hai toán hạng đều đúng. Bitwise &hoạt động theo cách tương tự: nó so sánh hai số từng chút một. Kết quả của sự so sánh này là số thứ ba. Ví dụ: lấy số 277 và 432: 100010101 - số 277 ở dạng nhị phân 110110000 - số 432 ở dạng nhị phân Tiếp theo, toán tử &so sánh bit đầu tiên của số trên với bit đầu tiên của số dưới. Vì đây là toán tử “AND” nên kết quả sẽ chỉ bằng 1 nếu cả hai bit đều bằng 1. Trong tất cả các trường hợp khác, kết quả sẽ là 0. 100010101 & 110110000 _______________ 100010000 - kết quả công việc & Trước tiên, chúng ta so sánh các bit đầu tiên của hai số với nhau, sau đó là bit thứ hai, thứ ba, v.v. Như bạn có thể thấy, chỉ trong hai trường hợp cả hai bit đều có số bằng 1 (bit thứ nhất và thứ năm). Kết quả của tất cả các so sánh khác là 0. Do đó, cuối cùng chúng ta nhận được số 100010000. Trong hệ thập phân, nó tương ứng với số 272. Hãy kiểm tra:
public class Main {

   public static void main(String[] args) {
       System.out.println(277&432);
   }
}
Đầu ra của bảng điều khiển:

272
  • |- theo bit “HOẶC”. Nguyên lý hoạt động là như nhau - chúng ta so sánh hai số từng chút một. Chỉ bây giờ nếu ít nhất một trong các bit bằng 1 thì kết quả sẽ bằng 1. Hãy xem xét các số giống nhau - 277 và 432:
100010101 | 110110000 _______________ 110110101 - kết quả của công việc | Ở đây kết quả khác: chỉ những bit có số 0 trong cả hai số vẫn là số 0. Kết quả của công việc là số 110110101. Trong hệ thập phân, nó tương ứng với số 437. Hãy kiểm tra:
public class Main {

   public static void main(String[] args) {
       System.out.println(277|432);
   }
}
Đầu ra của bảng điều khiển:

437
Chúng tôi đã tính toán mọi thứ một cách chính xác! :)
  • ^- HOẶC độc quyền theo bit (còn được gọi là XOR)
Chúng tôi chưa bao giờ gặp phải một nhà điều hành như vậy trước đây. Nhưng không có gì phức tạp về nó. Nó trông giống như một chữ “hoặc” thông thường. Sự khác biệt là một: trả về “hoặc” thông thường truenếu có ít nhất một toán hạng đúng. Nhưng không nhất thiết phải có một - nếu cả hai đều có true- thì kết quả là true. Nhưng “hoặc” độc quyền truechỉ trả về nếu một trong các toán hạng là đúng. Nếu cả hai toán hạng đều đúng thì toán hạng “hoặc” thông thường sẽ trả về true(“ít nhất một toán hạng là đúng”), nhưng toán hạng or sẽ trả về false. Đó là lý do tại sao nó được gọi là độc quyền. Biết nguyên tắc của các thao tác bitwise trước đó, bạn có thể dễ dàng tự mình thực hiện thao tác 277^432. Nhưng tốt hơn hết chúng ta hãy cùng nhau tìm hiểu lại một lần nữa :) 100010101 ^ 110110000 _______________ 010100101 - kết quả công việc ^ Đây là kết quả của chúng tôi. Những bit giống nhau ở cả hai số đều trả về 0 (công thức “một trong” không hoạt động). Nhưng những đội tạo thành cặp 0-1 hoặc 1-0 cuối cùng đã trở thành một đơn vị. Kết quả là chúng ta nhận được số 010100101. Trong hệ thập phân, nó tương ứng với số 165. Hãy xem liệu chúng ta đã tính đúng hay không:
public class Main {

   public static void main(String[] args) {
       System.out.println(277^432);
   }
}
Đầu ra của bảng điều khiển:

165
Siêu! Mọi thứ đúng như chúng ta nghĩ :) Bây giờ là lúc làm quen với các thao tác được gọi là dịch chuyển bit. Về nguyên tắc, cái tên đã nói lên điều đó. Chúng ta sẽ lấy một số số và di chuyển các bit của nó sang trái và phải :) Hãy xem nó trông như thế nào:

Sang trái

Sự dịch chuyển sang trái của các bit được biểu thị bằng dấu << Ví dụ:
public class Main {

   public static void main(String[] args) {
       int x = 64;//meaning
       int y = 3;//quantity

       int z = (x << y);
       System.out.println(Integer.toBinaryString(x));
       System.out.println(Integer.toBinaryString(z));
   }
}
Trong ví dụ này, số x=64được gọi là giá trị. Chúng ta sẽ thay đổi các bit của nó. Chúng ta sẽ dịch chuyển các bit sang trái (điều này có thể được xác định theo hướng của dấu <<) Trong hệ nhị phân, số 64 = 1000000 Số y=3được gọi là số lượng. Số lượng trả lời câu hỏi “các bit của một số nên được dịch chuyển bao nhiêu bit sang phải/trái x?” Trong ví dụ của chúng ta, chúng ta sẽ dịch chuyển chúng 3 bit sang trái. Để làm cho quá trình chuyển đổi rõ ràng hơn, chúng ta hãy nhìn vào bức tranh. Trong ví dụ của chúng tôi, chúng tôi sử dụng các số kiểu int. Int's chiếm 32 bit bộ nhớ máy tính. Số 64 ban đầu của chúng ta trông như thế này: Hoạt động theo bit - 2Và bây giờ, theo nghĩa đen của từ này, chúng ta lấy từng bit của mình và dịch nó sang trái 3 ô: Hoạt động theo bit - 3Đây là những gì chúng ta có. Như bạn có thể thấy, tất cả các bit của chúng ta đã dịch chuyển và 3 số 0 nữa đã được thêm vào từ bên ngoài phạm vi. 3 - bởi vì chúng ta đang dịch chuyển đi 3. Nếu chúng ta dịch chuyển đi 10, thì 10 số không sẽ được thêm vào. Vì vậy, biểu thức x << ycó nghĩa là “dịch chuyển các bit của một số хy ô sang trái”. Kết quả biểu thức của chúng ta là số 1000000000, số này trong hệ thập phân bằng 512. Hãy kiểm tra:
public class Main {

   public static void main(String[] args) {
       int x = 64;//meaning
       int y = 3;//quantity

       int z = (x << y);
       System.out.println(z);
   }
}
Đầu ra của bảng điều khiển:

512
Đúng rồi! Về lý thuyết, các bit có thể được dịch chuyển vô thời hạn. Nhưng vì chúng ta có số intnên chỉ có 32 ô. Trong số này, 7 đã có số 64 (1.000.000). Do đó, nếu chúng ta thực hiện, chẳng hạn như 27 ca sang trái, đơn vị duy nhất của chúng ta sẽ vượt quá phạm vi và "ghi đè". Sẽ chỉ còn lại số không!
public class Main {

   public static void main(String[] args) {
       int x = 64;//meaning
       int y = 26;//quantity

       int z = (x << y);
       System.out.println(z);
   }
}
Đầu ra của bảng điều khiển:

0
Đúng như chúng tôi mong đợi, cái đó đã vượt ra ngoài ô 32 bit và biến mất. Chúng tôi có một số 32 bit chỉ bao gồm các số 0. Hoạt động theo bit - 4Đương nhiên, trong hệ thập phân, nó tương ứng với 0. Một quy tắc đơn giản để ghi nhớ các phép dịch trái: Với mỗi lần dịch trái, số đó được nhân với 2. Ví dụ: hãy thử tính kết quả của biểu thức không có hình ảnh bằng bit 111111111 << 3 . nhân số 111111111 với 2 ba lần. Kết quả là chúng ta nhận được 888888888. Hãy viết mã và kiểm tra nó:
public class Main {

   public static void main(String[] args) {
       System.out.println(111111111 << 3);
   }
}
Đầu ra của bảng điều khiển:

888888888

Ca phải

Chúng được biểu thị bằng dấu hiệu >>. Họ làm điều tương tự, chỉ theo hướng khác! :) Chúng ta đừng phát minh lại bánh xe và thử làm điều này với cùng số int 64.
public class Main {

   public static void main(String[] args) {
       int x = 64;//meaning
       int y = 2;//quantity

       int z = (x >> y);
       System.out.println(z);
   }
}
Hoạt động theo bit - 5Hoạt động theo bit - 6Do dịch chuyển sang phải 2 đơn vị, hai số 0 tận cùng của số chúng ta nằm ngoài phạm vi và bị xóa. Chúng ta nhận được số 10000, trong hệ thập phân tương ứng với số 16. Xuất ra bảng điều khiển:

16
Một quy tắc đơn giản để ghi nhớ các ca phải: Mỗi ca phải chia cho hai, loại bỏ phần dư. Ví dụ: 35 >> 2 có nghĩa là chúng ta cần chia 35 cho 2 2 lần, loại bỏ phần dư 35/2 = 17(loại bỏ phần dư 1) 17:2 = 8(loại bỏ phần dư 1) Tổng 35 >> 2phải bằng 8. Kiểm tra:
public class Main {

   public static void main(String[] args) {
       System.out.println(35 >> 2);
   }
}
Đầu ra của bảng điều khiển:

8

Mức độ ưu tiên của các hoạt động trong Java

Khi bạn viết hoặc đọc mã, bạn sẽ thường gặp các biểu thức trong đó một số thao tác được thực hiện đồng thời. Điều rất quan trọng là phải hiểu chúng sẽ được thực hiện theo thứ tự nào, nếu không kết quả có thể không mong muốn. Vì có nhiều thao tác trong Java nên tất cả chúng đều được tách thành một bảng đặc biệt:

ưu tiên điều hành

Toán tử Quyền ưu tiên
hậu tố expr++ expr--
đơn nhất ++expr --expr +expr ~ !
nhân * / %
phụ gia + -
sự thay đổi << >> >>>
quan hệ < > <= >=ví dụ
bình đẳng == !=
theo bit VÀ &
độc quyền theo bit HOẶC ^
bao gồm từng bit HOẶC |
logic VÀ &&
logic HOẶC ||
ba loài ? :
phân công = += -= *= /= %= &= ^= |= <<= >>= >>>=
Tất cả các thao tác được thực hiện từ trái sang phải, nhưng có tính đến mức độ ưu tiên của chúng. Ví dụ: nếu chúng ta viết: int x = 6 - 4/2; đầu tiên phép chia (4/2) sẽ được thực hiện. Tuy đứng thứ hai nhưng cô ấy được ưu tiên cao hơn. Dấu ngoặc đơn hoặc dấu ngoặc vuông thay đổi mức độ ưu tiên tối đa. Bạn có thể nhớ điều này từ trường học. Ví dụ: nếu bạn thêm chúng vào một biểu thức: int x = (6 - 4)/2; phép trừ sẽ được thực hiện trước vì nó được tính trong ngoặc đơn. Toán tử logic có &&mức độ ưu tiên khá thấp, như có thể thấy từ bảng. Vì vậy, thường thì nó sẽ được thực thi sau cùng. Ví dụ: boolean x = 6 - 4/2 > 3 && 12*12 <= 119; Biểu thức này sẽ được thực thi như thế này:
  • 4/2 = 2

    boolean x = 6 - 2 > 3 && 12*12 <= 119;
  • 12*12 = 144

    boolean x = 6 - 2 > 3 && 144 <= 119;
  • 6-2 = 4

    boolean x = 4 > 3 && 144 <= 119;
  • Tiếp theo các toán tử so sánh sẽ được thực thi:

    4 > 3 = true

    boolean x = true && 144 <= 119;
  • 144 <= 119 = false

    boolean x = true && false;
  • Và cuối cùng, toán tử cuối cùng sẽ được thực thi &&.

    boolean x = true && false;

    boolean x = false;

    +Ví dụ: toán tử cộng ( ), có độ ưu tiên cao hơn toán tử so sánh !=(“không bằng”);

    Do đó trong biểu thức:

    boolean x = 7 != 6+1;

    đầu tiên phép toán 6+1 sẽ được thực hiện, sau đó kiểm tra 7!=7 (sai) và cuối cùng kết quả sẽ được gán cho falsebiến x. Nhiệm vụ thường có mức độ ưu tiên thấp nhất trong tất cả các hoạt động - hãy xem trong bảng.

Phù! Bài giảng của chúng tôi dài nhưng bạn đã làm được! Nếu bạn không hiểu đầy đủ một số phần của bài giảng này và các bài giảng trước, đừng lo lắng, chúng ta sẽ đề cập đến những chủ đề này nhiều lần trong tương lai. Dưới đây là một số liên kết hữu ích cho bạn:
  • Toán tử logic - Bài giảng JavaRush về các phép toán logic. Chúng tôi sẽ không sớm nhận được chúng, nhưng bạn có thể đọc chúng ngay bây giờ, sẽ không có hại gì cả
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION