Toán tử bitwise là gì?


129

Tôi là người viết mã chỉ để giải trí và chưa thực sự đào sâu vào nó trong môi trường học thuật hoặc chuyên nghiệp, vì vậy những thứ như các toán tử bitwise này thực sự thoát khỏi tôi.

Tôi đã đọc một bài viết về JavaScript, dường như hỗ trợ các hoạt động bitwise. Tôi liên tục thấy hoạt động này được đề cập ở những nơi và tôi đã cố gắng đọc để tìm hiểu chính xác nó là gì, nhưng dường như tôi không hiểu gì cả. Vậy chúng là gì? Ví dụ rõ ràng sẽ là tuyệt vời! : D

Chỉ cần thêm một vài câu hỏi - một số ứng dụng thực tế của hoạt động bitwise là gì? Khi nào bạn có thể sử dụng chúng?


2
Đối với các câu hỏi khác, bạn có thể muốn thêm một câu hỏi SO mới và tham khảo câu hỏi này. Có lẽ bạn sẽ có được một bộ câu trả lời tốt hơn theo cách đó.
Greg Hewgill

Câu trả lời:


186

Vì không ai nói về chủ đề tại sao những điều này hữu ích:

Tôi sử dụng các thao tác bitwise rất nhiều khi làm việc với cờ. Ví dụ: nếu bạn muốn chuyển một loạt cờ cho một thao tác (giả sử File.Open(), với chế độ Đọc và chế độ Viết đều được bật), bạn có thể chuyển chúng dưới dạng một giá trị. Điều này được thực hiện bằng cách gán cho mỗi cờ có thể là bit riêng của nó trong một bitet (byte, short, int hoặc long). Ví dụ:

 Read: 00000001
Write: 00000010

Vì vậy, nếu bạn muốn vượt qua đọc VÀ viết, bạn sẽ vượt qua (READ | WRITE) sau đó kết hợp cả hai thành

00000011

Mà sau đó có thể được giải mã ở đầu bên kia như:

if ((flag & Read) != 0) { //...

kiểm tra nào

00000011 &
00000001

trả về

00000001

không phải là 0, vì vậy cờ không chỉ định READ.

Bạn có thể sử dụng XOR để chuyển đổi các bit khác nhau. Tôi đã sử dụng điều này khi sử dụng cờ để chỉ định đầu vào định hướng (Lên, Xuống, Trái, Phải). Ví dụ: nếu một sprite đang di chuyển theo chiều ngang và tôi muốn nó quay lại:

     Up: 00000001
   Down: 00000010
   Left: 00000100
  Right: 00001000
Current: 00000100

Tôi chỉ đơn giản là XOR giá trị hiện tại với (LEFT | RIGHT) sẽ tắt LEFT và RIGHT, trong trường hợp này.

Bit Shifting rất hữu ích trong một số trường hợp.

x << y

giống như

x * 2 y

nếu bạn cần nhanh chóng nhân với một lũy thừa hai, nhưng coi chừng chuyển 1 bit thành bit trên cùng - điều này làm cho số âm trừ khi nó không được ký. Nó cũng hữu ích khi xử lý các kích thước khác nhau của dữ liệu. Ví dụ: đọc một số nguyên từ bốn byte:

int val = (A << 24) | (B << 16) | (C << 8) | D;

Giả sử rằng A là byte có ý nghĩa nhất và D ít nhất. Nó sẽ kết thúc như:

A = 01000000
B = 00000101
C = 00101011
D = 11100011
val = 01000000 00000101 00101011 11100011

Màu sắc thường được lưu trữ theo cách này (với byte đáng kể nhất bị bỏ qua hoặc được sử dụng làm Alpha):

A = 255 = 11111111
R = 21 = 00010101
G = 255 = 11111111
B = 0 = 00000000
Color = 11111111 00010101 11111111 00000000

Để tìm lại các giá trị, chỉ cần dịch chuyển các bit sang phải cho đến khi nó ở dưới cùng, sau đó che đi các bit có thứ tự cao hơn còn lại:

Int Alpha = Color >> 24
Int Red = Color >> 16 & 0xFF
Int Green = Color >> 8 & 0xFF
Int Blue = Color & 0xFF

0xFFcũng giống như 11111111. Vì vậy, về cơ bản, đối với Red, bạn sẽ làm điều này:

Color >> 16 = (filled in 00000000 00000000)11111111 00010101  (removed 11111111 00000000)
00000000 00000000 11111111 00010101 &
00000000 00000000 00000000 11111111 =
00000000 00000000 00000000 00010101 (The original value)

x << n, vậy n phải ở dạng 2 ^ giá trị?
Ahmed C

28

Điều đáng chú ý là các bảng chân lý một bit được liệt kê là các câu trả lời khác chỉ hoạt động trên một hoặc hai bit đầu vào tại một thời điểm. Điều gì xảy ra khi bạn sử dụng số nguyên, chẳng hạn như:

int x = 5 & 6;

Câu trả lời nằm ở phần mở rộng nhị phân của mỗi đầu vào:

  5 = 0 0 0 0 0 1 0 1
& 6 = 0 0 0 0 0 1 1 0
---------------------
      0 0 0 0 0 1 0 0

Mỗi cặp bit trong mỗi cột được chạy qua hàm "AND" để cung cấp bit đầu ra tương ứng trên dòng dưới cùng. Vì vậy, câu trả lời cho biểu thức trên là 4. CPU đã thực hiện (trong ví dụ này) 8 thao tác "VÀ" riêng biệt song song, một cho mỗi cột.

Tôi đề cập đến điều này bởi vì tôi vẫn nhớ có "AHA!" Khoảnh khắc khi tôi biết về điều này nhiều năm trước.


Wow, điều đó có ý nghĩa hơn rất nhiều bây giờ. Nghe có vẻ phức tạp hơn nhiều so với nó rõ ràng. Cảm ơn. Tôi không chắc nên chọn câu trả lời đúng vì có vô số câu trả lời hay và tôi không thể đưa ra ý kiến ​​như vậy .. cảm ơn
nhấp vào

27

Toán tử bitwise là toán tử hoạt động trên một bit tại một thời điểm.

AND chỉ là 1 nếu cả hai đầu vào của nó là 1.

HOẶC là 1 nếu một hoặc nhiều đầu vào của nó là 1.

XOR là 1 chỉ khi chính xác một trong những đầu vào của nó là 1.

KHÔNG là 1 chỉ khi đầu vào của nó là 0.

Đây có thể được mô tả tốt nhất như bảng sự thật. Các khả năng của đầu vào nằm ở trên cùng và bên trái, bit kết quả là một trong bốn (hai trong trường hợp KHÔNG vì nó chỉ có một giá trị) được hiển thị tại giao điểm của hai đầu vào.

AND|0 1      OR|0 1
---+----    ---+----
  0|0 0       0|0 1
  1|0 1       1|1 1

XOR|0 1     NOT|0 1
---+----    ---+---
  0|0 1        |1 0
  1|1 0

Một ví dụ là nếu bạn chỉ muốn 4 bit thấp hơn của một số nguyên, bạn VÀ nó với 15 (nhị phân 1111), vì vậy:

    203: 1100 1011
AND  15: 0000 1111
------------------
 IS  11: 0000 1011

16

Đây là các toán tử bitwise, tất cả được hỗ trợ trong JavaScript:

  • op1 & op2- ANDToán tử so sánh hai bit và tạo kết quả là 1 nếu cả hai bit là 1; mặt khác, nó trả về 0.

  • op1 | op2- ORToán tử so sánh hai bit và tạo kết quả là 1 nếu các bit là bổ sung; mặt khác, nó trả về 0.

  • op1 ^ op2- EXCLUSIVE-ORToán tử so sánh hai bit và trả về 1 nếu một trong hai bit là 1 và nó cho 0 nếu cả hai bit là 0 hoặc 1.

  • ~op1- COMPLEMENTToán tử được sử dụng để đảo ngược tất cả các bit của toán hạng.

  • op1 << op2- SHIFT LEFTToán tử di chuyển các bit sang trái, loại bỏ bit xa bên trái và gán cho bit ngoài cùng bên phải một giá trị 0. Mỗi lần di chuyển sang bên trái nhân op1 hiệu quả bằng 2.

  • op1 >> op2- SHIFT RIGHTToán tử di chuyển các bit sang phải, loại bỏ bit ngoài cùng bên phải và gán cho bit ngoài cùng bên trái một giá trị 0. Mỗi lần di chuyển sang phải sẽ chia op1 một cách hiệu quả. Các bit dấu bên trái nhất được bảo tồn.

  • op1 >>> op2- Toán tử SHIFT RIGHT- ZERO FILLdi chuyển các bit sang phải, loại bỏ bit ngoài cùng bên phải và gán cho bit ngoài cùng bên trái một giá trị 0. Mỗi lần di chuyển sang phải sẽ chia op1 một cách hiệu quả. Các bit dấu bên trái nhất được loại bỏ.


"Nếu các bit là bổ sung" - waht?
Andrey Tyukin

@AndreyTyukin hai bit là bổ sung nếu một trong số đó là 1 và bit kia là 0.
Jeff Hillman

@JeffHillman Theo mô tả của bạn trong bình luận, 1 và 1 không phải là "bổ sung". Sau đó, tôi không rõ tại sao 1 | 1cho 1và không 0, và |sau đó được cho là khác biệt như thế nào ^. Tôi đã phải sử dụng Q / A này làm mục tiêu trùng lặp vài ngày trước và tôi ước rằng sau 10 năm, người ta sẽ có một bản sao chính tắc rõ ràng hơn cho loại câu hỏi này.
Andrey Tyukin

4

Để phá vỡ nó nhiều hơn một chút, nó có liên quan nhiều đến biểu diễn nhị phân của giá trị được đề cập.

Ví dụ: (ở dạng thập phân):
x = 8
y = 1

sẽ đi ra (trong nhị phân):
x = 1000
y = 0001

Từ đó, bạn có thể thực hiện các thao tác tính toán như 'và' hoặc 'hoặc'; trong trường hợp này:
x | y =
1000 
0001 |
------
1001

hoặc ... 9 số thập phân

Hi vọng điêu nay co ich.


|là một hoạt động OR?
Si8

Vì một số lý do, điều này có ý nghĩa nhất đối với tôi. Vẫn không chắc chắn về x | y = 1000 0001 |phần này
samayo 17/03/2017

4

Khi thuật ngữ "bitwise" được đề cập, đôi khi làm rõ rằng đó không phải là toán tử "logic".

Ví dụ, trong JavaScript, các toán tử bitwise coi toán hạng của chúng là một chuỗi gồm 32 bit (số không và số 0) ; trong khi đó, các toán tử logic thường được sử dụng với các giá trị Boolean (logic) nhưng có thể hoạt động với các kiểu không Boolean.

Lấy expr1 && expr2 làm ví dụ.

Trả về expr1 nếu nó có thể được chuyển đổi thành false; mặt khác, trả về expr2. Do đó, khi được sử dụng với các giá trị Boolean, && trả về true nếu cả hai toán hạng đều đúng; nếu không, trả về false.

a = "Cat" && "Dog"     // t && t returns Dog
a = 2 && 4     // t && t returns 4

Như những người khác đã lưu ý, 2 & 4 là bit AND, vì vậy nó sẽ trả về 0.

Bạn có thể sao chép phần sau vào test.html hoặc một cái gì đó và kiểm tra:

<html>
<body>
<script>
    alert("\"Cat\" && \"Dog\" = " + ("Cat" && "Dog") + "\n"
        + "2 && 4 = " + (2 && 4) + "\n"
        + "2 & 4 = " + (2 & 4));
</script>

3

Trong lập trình máy tính kỹ thuật số, một phép toán bit hoạt động trên một hoặc nhiều mẫu bit hoặc số nhị phân ở cấp độ của các bit riêng lẻ của chúng. Đây là một hành động nhanh, nguyên thủy được bộ xử lý hỗ trợ trực tiếp và được sử dụng để thao tác các giá trị để so sánh và tính toán.

hoạt động :

  • bitwise VÀ

  • bitwise HOẶC

  • bitwise KHÔNG

  • bitwise XOR

  • Vân vân

Danh sách mục

    AND|0 1        OR|0 1 
    ---+----      ---+---- 
      0|0 0         0|0 1 
      1|0 1         1|1 1 

   XOR|0 1        NOT|0 1 
   ---+----       ---+--- 
     0|0 1           |1 0 
     1|1 0

Ví dụ.

    203: 1100 1011
AND  15: 0000 1111
------------------
  =  11: 0000 1011

Công dụng của toán tử bitwise

  • Các toán tử dịch chuyển trái và dịch chuyển phải tương đương với phép nhân và chia cho x * 2 y tương ứng.

Ví dụ.

int main()
{
     int x = 19;
     printf ("x << 1 = %d\n" , x <<1);
     printf ("x >> 1 = %d\n", x >>1);
     return 0;
}
// Output: 38 9
  • Toán tử & có thể được sử dụng để nhanh chóng kiểm tra xem một số là số lẻ hay chẵn

Ví dụ.

int main()
{
    int x = 19;
    (x & 1)? printf("Odd"): printf("Even");
    return 0;
 }
// Output: Odd
  • Tìm nhanh tối thiểu x và y mà không cần if elsekhai báo

Ví dụ.

int min(int x, int y)
{
    return y ^ ((x ^ y) & - (x < y))
}
  • Chuyển đổi thập phân sang nhị phân

Ví dụ.

#include <stdio.h>
int main ()
{
    int n , c , k ;
    printf("Enter an integer in decimal number system\n " ) ;
    scanf( "%d" , & n );
    printf("%d in binary number
    system is: \n " , n ) ;
    for ( c = 31; c >= 0 ; c -- )
    {
         k = n >> c ;
         if ( k & 1 )
              printf("1" ) ;
         else
              printf("0" ) ;
      }
      printf(" \n " );
      return 0 ;
}
  • Mã hóa cổng XOR là kỹ thuật phổ biến, bởi vì nó được sử dụng bởi người lập trình.
  • Toán tử bitwise XOR là toán tử hữu ích nhất từ ​​góc độ phỏng vấn kỹ thuật.

dịch chuyển bitwise chỉ hoạt động với số + ve

Ngoài ra có một phạm vi sử dụng rộng rãi của logic bitwise


"Sự đồng điệu và thực sự ..."?
Jonathan Cross

The left-shift and right-shift operators are equivalent to multiplication and division by x * 2y respectively.Đúng rồi! muyiy.cn/question/program/102.html
xgqfrms

giải pháp của tôi thay thế.it /@xgqfrms / từ
xgqfrms

1

Nó có thể giúp để nghĩ về nó theo cách này. Đây là cách AND (&) hoạt động:

Về cơ bản nó nói là cả hai số này, vì vậy nếu bạn có hai số 5 và 3, chúng sẽ được chuyển đổi thành nhị phân và máy tính sẽ nghĩ

         5: 00000101
         3: 00000011

cả hai đều là: 00000001 0 là sai, 1 là đúng

Vì vậy, AND của 5 và 3 là một. Toán tử OR (|) thực hiện điều tương tự ngoại trừ chỉ một trong các số phải là một cho đầu ra 1, không phải cả hai.


-5

Tôi đã nghe về việc các nhà khai thác bitwise JavaScript chậm như thế nào. Tôi đã thực hiện một số bài kiểm tra cho bài đăng trên blog mới nhất của mình và phát hiện ra chúng nhanh hơn 40% đến 80% so với phương pháp số học trong một số bài kiểm tra. Có lẽ họ đã từng chậm. Trong các trình duyệt hiện đại, tôi yêu chúng.

Tôi có một trường hợp trong mã của tôi sẽ nhanh hơn và dễ đọc hơn vì điều này. Tôi sẽ mở mắt ra để biết thêm.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.