Các trường hợp sử dụng trong thế giới thực của các toán tử bitwise [đã đóng]


224

Một số trường hợp sử dụng trong thế giới thực của các toán tử bitwise sau đây là gì?

  • XOR
  • KHÔNG PHẢI
  • HOẶC LÀ
  • Ca trái / phải

1
Tôi nhớ khi tôi mới biết về chúng, có vẻ như chúng chỉ được sử dụng cho cấp độ thấp ... nhưng kể từ đó chúng được nhập bằng hộp công cụ và tôi sử dụng chúng thường xuyên, kể cả khi thực hiện lập trình "cấp cao". Bây giờ họ giống như + và * đối với tôi.
Sồi

2
@Anon.: Trong suy nghĩ của tôi, thế giới thực được cho là có ý nghĩa gì đó ngoài lập trình cấp thấp, đó là cách sử dụng rõ ràng nhất của các toán tử bitwise.
Olivier Lalonde



Cũng có thể sử dụng XOR nhị phân để tìm một số bị thiếu trong một hoán vị: martinkysel.com/codility-permmissingelem-solution
Janac Meena

Câu trả lời:


216
  • Các trường bit (cờ)
    Chúng là cách hiệu quả nhất để thể hiện một cái gì đó có trạng thái được xác định bởi một số thuộc tính "có hoặc không". ACL là một ví dụ tốt; nếu bạn có 4 quyền riêng biệt (đọc, viết, thực thi, thay đổi chính sách), tốt hơn hết là lưu trữ tệp này trong 1 byte thay vì lãng phí 4. Chúng có thể được ánh xạ thành các loại liệt kê bằng nhiều ngôn ngữ để thuận tiện hơn.

  • Giao tiếp qua cổng / ổ cắm
    Luôn liên quan đến tổng kiểm, chẵn lẻ, bit dừng, thuật toán điều khiển luồng, v.v., thường phụ thuộc vào giá trị logic của từng byte thay vì giá trị số, vì phương tiện chỉ có thể truyền một bit tại một thời gian.

  • Nén, mã hóa
    Cả hai điều này phụ thuộc rất nhiều vào thuật toán bitwise. Nhìn vào thuật toán deflate cho một ví dụ - mọi thứ đều tính bằng bit, không phải byte.

  • Máy trạng thái hữu hạn
    Tôi đang nói chủ yếu về loại được nhúng trong một số phần cứng, mặc dù chúng cũng có thể được tìm thấy trong phần mềm. Đây là những tổ hợp trong tự nhiên - họ theo nghĩa đen có thể nhận được "biên soạn" xuống đến một loạt các cổng logic, vì vậy họ phải được diễn tả như AND, OR, NOTvv

  • Đồ họa Hầu như không có đủ không gian ở đây để đi vào mọi khu vực nơi các toán tử này được sử dụng trong lập trình đồ họa. XOR(hoặc ^) đặc biệt thú vị ở đây vì áp dụng cùng một đầu vào lần thứ hai sẽ hoàn tác lần đầu tiên. GUI cũ hơn được sử dụng để dựa vào điều này để làm nổi bật lựa chọn và các lớp phủ khác, để loại bỏ sự cần thiết phải vẽ lại tốn kém. Chúng vẫn hữu ích trong các giao thức đồ họa chậm (tức là máy tính để bàn từ xa).

Đó chỉ là một vài ví dụ đầu tiên tôi nghĩ ra - đây không phải là một danh sách đầy đủ.


Xin chào @Aaronaught, Bạn đã thực sự chia sẻ kiến ​​thức rất tốt với chúng tôi. Tôi muốn biết thêm về các trường hợp trong thế giới thực của Nhà điều hành Bitwise. Bạn có phiền khi chia sẻ tài liệu tham khảo của bạn với chúng tôi, sẽ thực sự hữu ích để đọc về nó nhiều hơn.
Heena Hussain

Các hoạt động bitwise có hữu ích cho các tính toán véc tơ không?
Aaron Franke

47

Có lạ không?

(value & 0x1) > 0

Là nó chia hết cho hai (chẵn)?

(value & 0x1) == 0

3
Tùy thuộc vào giá trị ngôn ngữ của bạn & 0x1> 0 có thể được phân tích cú pháp dưới dạng giá trị & (0x1> 0)
leeeroy

3
@leeeroy - Đúng vậy. Đã thêm một số parens.
Seth

Các trình tối ưu hóa hiện đại sẽ tự động chuyển đổi các biểu thức như (giá trị% 2)! = 0 thành các biểu thức trên. godbolt.org/z/mYEBH4
Ferrarezi

26

Đây là một số thành ngữ phổ biến xử lý các cờ được lưu trữ dưới dạng các bit riêng lẻ.

enum CDRIndicators {
  Local = 1 << 0,
  External = 1 << 1,
  CallerIDMissing = 1 << 2,
  Chargeable = 1 << 3
};

unsigned int flags = 0;

Đặt cờ có thể tính phí:

flags |= Chargeable;

Xóa cờ CallerIDMissing:

flags &= ~CallerIDMissing;

Kiểm tra xem CallerIDMissing và Chargeable có được đặt hay không:

if((flags & (CallerIDMissing | Chargeable )) == (CallerIDMissing | Chargeable)) {

}

25

Tôi đã sử dụng các thao tác bitwise trong việc triển khai mô hình bảo mật cho CMS. Nó có các trang mà người dùng có thể truy cập nếu họ ở trong các nhóm thích hợp. Một người dùng có thể ở nhiều nhóm, vì vậy chúng tôi cần kiểm tra xem có sự giao thoa giữa các nhóm người dùng và các nhóm trang không. Vì vậy, chúng tôi đã gán cho mỗi nhóm một mã định danh sức mạnh 2 duy nhất, ví dụ:

Group A = 1 --> 00000001
Group B = 2 --> 00000010
Group C = 3 --> 00000100

Chúng tôi HOẶC các giá trị này cùng nhau và lưu trữ giá trị (dưới dạng một int) với trang. Ví dụ: nếu một nhóm A & B có thể được truy cập một trang, chúng tôi lưu trữ giá trị 3 (trong nhị phân là 00000011) làm điều khiển truy cập trang. Theo cùng một cách, chúng tôi lưu trữ một giá trị định danh nhóm ORed với người dùng để thể hiện họ thuộc nhóm nào.

Vì vậy, để kiểm tra xem một người dùng nhất định có thể truy cập một trang nhất định hay không, bạn chỉ cần VÀ các giá trị với nhau và kiểm tra xem giá trị có khác không. Điều này rất nhanh vì kiểm tra này được thực hiện trong một hướng dẫn duy nhất, không lặp, không có cơ sở dữ liệu khứ hồi.


24

Lập trình cấp thấp là một ví dụ tốt. Ví dụ, bạn có thể cần ghi một bit cụ thể vào thanh ghi ánh xạ bộ nhớ để làm cho một số phần cứng làm những gì bạn muốn:

volatile uint32_t *register = (volatile uint32_t *)0x87000000;
uint32_t          value;
uint32_t          set_bit   = 0x00010000;
uint32_t          clear_bit = 0x00001000;

value = *register;            // get current value from the register
value = value & ~clear_bit;   // clear a bit
value = value | set_bit;      // set a bit
*register = value;            // write it back to the register

Ngoài ra, htonl()htons()được thực hiện bằng cách sử dụng& và các |toán tử (trên các máy có tuổi thọ (thứ tự Byte) không khớp với thứ tự mạng):

#define htons(a) ((((a) & 0xff00) >> 8) | \
                  (((a) & 0x00ff) << 8))

#define htonl(a) ((((a) & 0xff000000) >> 24) | \
                  (((a) & 0x00ff0000) >>  8) | \
                  (((a) & 0x0000ff00) <<  8) | \
                  (((a) & 0x000000ff) << 24))

7
Không phải ai cũng nói chuyện trong máy. Ví dụ thứ hai của bạn đang làm gì?
ChaosPandion

7
htons()htonl()là các hàm POSIX để hoán đổi a shorthoặc a longtừ hendianness của máy chủ ( ) sang nthứ tự byte của mạng ( ).
Carl Norum

Bạn có thể sử dụng một phương pháp tương tự để thực hiện đảo ngược bit trong các hoạt động O (logN).
Mike DeSimone

lol khi tôi lần đầu tiên nhìn thấy điều này tôi nghĩ rằng nó là lắp ráp!
0x499602D2

Không htonl()intgiá trị 32 bit ? longcó nghĩa là 64 bit trong nhiều ngôn ngữ.
Aaron Franke

21

Tôi sử dụng chúng để lấy các giá trị RGB (A) từ các giá trị màu được đóng gói, chẳng hạn.


Và nó thực sự nhanh chóng!
Callum Rogers

Trong C #, đây là một trong những trường hợp thực sự là giải pháp tốt nhất, cho khả năng đọc và tốc độ.
Thuyền trưởngCasey

4
Trên máy của tôi, (a & b) >> cnhanh hơn gấp 5 lần a % d / e(cả hai cách để trích xuất một giá trị màu duy nhất từ ​​một int đại diện cho ARGB). Tương ứng, 6,7 và 35,2 cho 1 tỷ lần lặp.
Benji XVI

@BenjiXVI C # không có tối ưu hóa trình biên dịch cho việc này. Lý do bạn quan sát thấy sự khác biệt về tốc độ là bởi vì, trong C #, %không phải là toán tử Modulus, nó là toán tử còn lại. Chúng tương đương với các giá trị dương nhưng khác với giá trị âm. Nếu bạn cung cấp các hạn chế thích hợp (vượt qua uintthay vì intví dụ) thì hai ví dụ sẽ có cùng tốc độ.
Aaron Franke

xin lỗi tôi biết đó là một thời gian dài. Bạn có thể vui lòng chỉ ra một ví dụ về cách sử dụng chúng để nhận từng giá trị RGB không?
Jinx

14

Khi tôi có một loạt các cờ boolean, tôi muốn lưu trữ tất cả chúng trong một int.

Tôi lấy chúng ra bằng bitwise-AND. Ví dụ:

int flags;
if (flags & 0x10) {
  // Turn this feature on.
}

if (flags & 0x08) {
  // Turn a second feature on.
}

Vân vân.


23
Hy vọng rằng đó thực sự là các hằng số trong mã thực của bạn chứ không phải số ma thuật :)
Earlz

1
Một ví dụ về việc sử dụng các cờ boolean trong thế giới không cấp thấp đang làm mọi thứ với các nền tảng GUI khác nhau. Chẳng hạn, bạn có thể sử dụng my_button.Style | = STYLE_DISABLED để tắt nó đi.
MauriceL

1
Tôi biết chủ đề này là bất khả tri ngôn ngữ, nhưng C cung cấp một cách dễ dàng để làm điều này với các trường bit để bạn có thể sử dụng những thứ như if (flags.feature_one_is_one) { // turn on feature }. Đó là trong tiêu chuẩn ANSI C, vì vậy tính di động không phải là một vấn đề.
cảnh sát

thật tuyệt khi nhận được lời giải thích về đoạn mã này làm gì, tại sao các cờ không được khởi tạo, ý bạn là gì khi "lưu trữ tất cả trong một int", ký hiệu được sử dụng là gì ...
Angelo Oparah 17/03

12

& = AND:
Che dấu các bit cụ thể.
Bạn đang xác định các bit cụ thể sẽ được hiển thị hoặc không được hiển thị. 0x0 & x sẽ xóa tất cả các bit trong một byte trong khi 0xFF sẽ không thay đổi x. 0x0F sẽ hiển thị các bit ở mức thấp hơn.

Chuyển đổi:
Để truyền các biến ngắn hơn thành các biến dài hơn có nhận dạng bit, cần điều chỉnh các bit vì -1 trong một int là 0xFFFFFFFF trong khi -1 trong một dài là 0xFFFFFFFFFFFFFFFF. Để giữ bản sắc, bạn áp dụng mặt nạ sau khi chuyển đổi.

| = HOẶC
Đặt bit. Các bit sẽ được đặt độc lập nếu chúng đã được đặt. Nhiều cơ sở dữ liệu (bitfield) có các cờ như IS_HSET = 0, IS_VSET = 1 có thể được đặt độc lập. Để đặt cờ, bạn áp dụng IS_HSET | IS_VSET (Trong C và lắp ráp, điều này rất thuận tiện để đọc)

^ = XOR
Tìm các bit giống nhau hoặc khác nhau.

~ = KHÔNG
Lật bit.

Nó có thể được chỉ ra rằng tất cả các hoạt động bit cục bộ có thể có thể được thực hiện bởi các hoạt động này. Vì vậy, nếu bạn thích, bạn có thể thực hiện một lệnh ADD chỉ bằng các thao tác bit.

Một số hack tuyệt vời:

http://www.ugcs.caltech.edu/~wnoise/base2.html
http://www.jjj.de/bitwizardry/bitwizardrypage.html


Sau đây là một liên kết đưa ra các ví dụ tuyệt vời về việc sử dụng các toán tử bitwise trong AS3 cho các phép toán siêu nhanh (nhưng nó có thể được áp dụng cho hầu hết các ngôn ngữ): lab.poly Cross.de/2007/05/10/bitwise-gems-fast- toán học số nguyên
tích hợp nhiều vào

Tôi nghĩ "KHÔNG" nên = ~, không |=, đó là HOẶC.
Mike DeSimone

& = AND- Tại sao tôi muốn xóa tất cả các bit, tại sao tôi lại muốn có một phiên bản chưa sửa đổi của byte và tôi phải làm gì với nibble thấp hơn?
nhầm

1
@ nhầm00 phải, cách nhanh hơn / đơn giản hơn để vô hiệu hóa một kết quả là xorchính nó. Tôi có thể nghĩ ra khá nhiều lý do mà bạn có thể muốn trích xuất phần thấp hơn. Đặc biệt nếu nibble thấp hơn đó là một phần của cấu trúc dữ liệu và bạn muốn sử dụng nó làm mặt nạ hoặc ORvới cấu trúc khác.
James M. Lay

11

Mã hóa là tất cả các hoạt động bitwise.


4
Có thật không? Việc triển khai mã hóa có khả năng sử dụng các bit bit, nhưng thuật toán mã hóa thường được mô tả bằng thuật ngữ số và không phải là biểu diễn bit.
Constantin

1
Vậy bạn sẽ làm gì với các thuật toán khác ngoài việc thực hiện chúng? Tôi tò mò.
đệ quy

2
@Constantin: Xem, ví dụ, mô tả về cách triển khai DES: ( en.wikipedia.org/wiki/ mẹo
Wayne Conrad

1
@recursive, Nếu bạn hỏi về cá nhân tôi - tôi không thiết kế các thuật toán mã hóa cũng như không triển khai chúng. Nhưng mọi người làm nhiều việc, như phân tích chúng cho những điểm yếu về mặt lý thuyết.
Constantin

@Constantin: hãy xem cái này, đây chỉ là một ví dụ trong số nhiều thuật toán mã hóa thường được mô tả: en.wikipedia.org/wiki/Substlation_box
SyntaxT3rr0r

9

Bạn có thể sử dụng chúng như một cách nhanh chóng và bẩn để băm dữ liệu.

int a = 1230123;
int b = 1234555;
int c = 5865683;
int hash = a ^ b ^ c;

8

Tôi chỉ sử dụng bitwise-XOR (^ ) khoảng ba phút trước để tính toán tổng kiểm tra cho giao tiếp nối tiếp với PLC ...


7

Bitwise & được sử dụng để che / trích xuất một phần nhất định của một byte.

1 biến byte

 01110010
&00001111 Bitmask of 0x0F to find out the lower nibble
 --------
 00000010

Đặc biệt toán tử dịch chuyển (<< >>) thường được sử dụng để tính toán.


6

Đây là một ví dụ để đọc màu từ hình ảnh bitmap ở định dạng byte

byte imagePixel = 0xCCDDEE; /* Image in RRGGBB format R=Red, G=Green, B=Blue */

//To only have red
byte redColour = imagePixel & 0xFF0000; /*Bitmasking with AND operator */

//Now, we only want red colour
redColour = (redColour >> 24) & 0xFF;  /* This now returns a red colour between 0x00 and 0xFF.

Tôi hy vọng ví dụ nhỏ này sẽ giúp ....


5

Trong thế giới trừu tượng của ngôn ngữ hiện đại ngày nay, không quá nhiều. Tệp IO là một cách dễ dàng xuất hiện trong đầu, mặc dù đó là việc thực hiện các thao tác bitwise trên một cái gì đó đã được triển khai và không thực hiện một cái gì đó sử dụng các hoạt động bitwise. Tuy nhiên, như một ví dụ dễ hiểu, mã này thể hiện việc loại bỏ thuộc tính chỉ đọc trên một tệp (để nó có thể được sử dụng với FileStream mới chỉ định FileMode.Create) trong c #:

//Hidden files posses some extra attibutes that make the FileStream throw an exception
//even with FileMode.Create (if exists -> overwrite) so delete it and don't worry about it!
if(File.Exists(targetName))
{
    FileAttributes attributes = File.GetAttributes(targetName);

    if ((attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
        File.SetAttributes(targetName, attributes & (~FileAttributes.ReadOnly));

    File.Delete(targetName);
}

Theo như triển khai tùy chỉnh, đây là một ví dụ gần đây: Tôi đã tạo một "trung tâm thông báo" để gửi tin nhắn an toàn từ một cài đặt ứng dụng phân tán của chúng tôi sang ứng dụng khác. Về cơ bản, nó tương tự như email, hoàn chỉnh với Hộp thư đến, Hộp thư đi, Đã gửi, v.v., nhưng nó cũng được phân phối đảm bảo với biên nhận đã đọc, do đó, có thêm các thư mục con ngoài "hộp thư đến" và "đã gửi". Số tiền này là một yêu cầu đối với tôi để định nghĩa chung chung "trong hộp thư đến" hoặc "trong thư mục đã gửi" là gì. Trong thư mục đã gửi, tôi cần biết những gì đã đọc và những gì chưa đọc. Trong số những gì chưa đọc, tôi cần biết những gì đã nhận và những gì không nhận được. Tôi sử dụng thông tin này để xây dựng một mệnh đề động trong đó lọc một nguồn dữ liệu cục bộ và hiển thị thông tin phù hợp.

Đây là cách enum được kết hợp với nhau:

    public enum MemoView :int
    {
        InboundMemos = 1,                   //     0000 0001
        InboundMemosForMyOrders = 3,        //     0000 0011
        SentMemosAll = 16,                  //     0001 0000
        SentMemosNotReceived = 48,          //     0011
        SentMemosReceivedNotRead = 80,      //     0101
        SentMemosRead = 144,                //     1001
        Outbox = 272,                       //0001 0001 0000
        OutBoxErrors = 784                  //0011 0001 0000
    }

Bạn có thấy những gì nó làm? Bằng cách anding (&) với giá trị enum "Hộp thư đến", InboundMemos, tôi biết rằng InboundMemosForMyOrder nằm trong hộp thư đến.

Đây là phiên bản rút gọn của phương thức xây dựng và trả về bộ lọc xác định chế độ xem cho thư mục hiện được chọn:

    private string GetFilterForView(MemoView view, DefaultableBoolean readOnly)
    {
        string filter = string.Empty;
        if((view & MemoView.InboundMemos) == MemoView.InboundMemos)
        {
            filter = "<inbox filter conditions>";

            if((view & MemoView.InboundMemosForMyOrders) == MemoView.InboundMemosForMyOrders)
            {
                filter += "<my memo filter conditions>";
            }
        }
        else if((view & MemoView.SentMemosAll) == MemoView.SentMemosAll)
        {
            //all sent items have originating system = to local
            filter = "<memos leaving current system>";

            if((view & MemoView.Outbox) == MemoView.Outbox)
            {
                ...
            }
            else
            {
                //sent sub folders
                filter += "<all sent items>";

                if((view & MemoView.SentMemosNotReceived) == MemoView.SentMemosNotReceived)
                {
                    if((view & MemoView.SentMemosReceivedNotRead) == MemoView.SentMemosReceivedNotRead)
                    {
                        filter += "<not received and not read conditions>";
                    }
                    else
                        filter += "<received and not read conditions>";
                }
            }
        }

        return filter;
    }

Vô cùng đơn giản, nhưng việc thực hiện gọn gàng ở mức độ trừu tượng thường không yêu cầu các thao tác bitwise.


4

Mã hóa Base64 là một ví dụ. Mã hóa Base64 được sử dụng để thể hiện dữ liệu nhị phân dưới dạng ký tự có thể in được để gửi qua hệ thống email (và các mục đích khác). Mã hóa Base64 chuyển đổi một chuỗi các byte 8 bit thành các chỉ mục tra cứu ký tự 6 bit. Các hoạt động bit, dịch chuyển, và, hoặc không, rất hữu ích để thực hiện các hoạt động bit cần thiết cho mã hóa và giải mã Base64.

Tất nhiên đây chỉ là 1 trong vô số ví dụ.



4

Thông thường các thao tác bitwise nhanh hơn so với thực hiện nhân / chia. Vì vậy, nếu bạn cần nhân một biến x với 9, bạn sẽ thực hiện x<<3 + xnhanh hơn một vài chu kỳx*9 . Nếu mã này nằm trong ISR, bạn sẽ tiết kiệm được thời gian phản hồi.

Tương tự như vậy nếu bạn muốn sử dụng một mảng như một hàng đợi tròn, nó sẽ nhanh hơn (và thanh lịch hơn) để xử lý các gói kiểm tra xung quanh với các thao tác khôn ngoan. (kích thước mảng của bạn phải là lũy thừa 2). Ví dụ :, bạn có thể sử dụng tail = ((tail & MASK) + 1)thay vìtail = ((tail +1) < size) ? tail+1 : 0 , nếu bạn muốn chèn / xóa.

Ngoài ra nếu bạn muốn một cờ lỗi giữ nhiều mã lỗi cùng nhau, mỗi bit có thể giữ một giá trị riêng. Bạn có thể VÀ nó với mỗi mã lỗi riêng lẻ dưới dạng kiểm tra. Điều này được sử dụng trong mã lỗi Unix.

Ngoài ra một bitmap n-bit có thể là một cấu trúc dữ liệu thực sự tuyệt vời và nhỏ gọn. Nếu bạn muốn phân bổ một nhóm tài nguyên có kích thước n, chúng ta có thể sử dụng một bit n để biểu thị trạng thái hiện tại.


3

Không ai có vẻ đã đề cập đến toán học điểm cố định.

(Vâng, tôi già rồi, được chứ?)


3

Là một số xcó sức mạnh bằng 2? (Ví dụ, hữu ích trong các thuật toán tăng bộ đếm và một hành động chỉ được thực hiện với số lần logarit)

(x & (x - 1)) == 0

Đó là bit cao nhất của một số nguyên x? (Ví dụ, điều này có thể được sử dụng để tìm công suất tối thiểu là 2 lớn hơn x)

x |= (x >>  1);
x |= (x >>  2);
x |= (x >>  4);
x |= (x >>  8);
x |= (x >> 16);
return x - (x >>> 1); // ">>>" is unsigned right shift

Đó là 1bit thấp nhất của một số nguyên x? (Giúp tìm số lần chia hết cho 2.)

x & -x

dịch chuyển bên phải không dấu được thực hiện trong C bằng cách chuyển LHS sang loại không dấu. Công thức cuối cùng của bạn không tìm thấy bit [set] thấp nhất, nó sẽ kiểm tra xem X có phải là lũy thừa của 2. Để tìm bit được đặt thấp nhất hay không, hãy làm x & -x.
Potatoswatter

Hmm, bạn đã đúng, bằng cách nào đó tôi đã thay thế x & -x bằng đoạn trích đầu tiên, thx để chỉnh sửa
Dimitris Andreou

3

Toán tử bitwise rất hữu ích cho việc lặp các mảng có độ dài bằng 2. Như nhiều người đã đề cập, toán tử bitwise cực kỳ hữu ích và được sử dụng trong Cờ , Đồ họa , Mạng , Mã hóa . Không chỉ vậy, nhưng chúng cực kỳ nhanh. Sử dụng yêu thích cá nhân của tôi là lặp một mảng mà không có điều kiện . Giả sử bạn có một mảng dựa trên chỉ mục 0 (ví dụ: chỉ mục của phần tử đầu tiên là 0) và bạn cần lặp nó vô thời hạn. Bởi vô thời hạn tôi có nghĩa là đi từ yếu tố đầu tiên đến cuối cùng và trở lại đầu tiên. Một cách để thực hiện điều này là:

int[] arr = new int[8];
int i = 0;
while (true) {
    print(arr[i]);
    i = i + 1;
    if (i >= arr.length) 
        i = 0;
}

Đây là phương pháp đơn giản nhất, nếu bạn muốn tránh nếu tuyên bố, bạn có thể sử dụng mô đun cách tiếp cận như vậy:

int[] arr = new int[8];
int i = 0;
while (true) {
    print(arr[i]);
    i = i + 1;
    i = i % arr.length;
}

Mặt trái của hai phương thức này là toán tử mô đun là đắt tiền, vì nó tìm kiếm phần còn lại sau khi chia số nguyên. Và phương pháp đầu tiên chạy một nếu tuyên bố trên mỗi lần lặp. Tuy nhiên, với toán tử bitwise nếu độ dài của mảng của bạn là lũy thừa bằng 2, bạn có thể dễ dàng tạo ra một chuỗi như 0 .. length - 1bằng cách sử dụng &toán tử (bitwise và) như vậy i & length. Vì vậy, biết điều này, mã từ trên trở thành

int[] arr = new int[8];
int i = 0;
while (true){
    print(arr[i]);
    i = i + 1;
    i = i & (arr.length - 1);
}

Đây là cách nó làm việc. Trong định dạng nhị phân, mọi số có sức mạnh bằng 2 trừ đi 1 chỉ được biểu thị bằng số. Ví dụ 3 trong nhị phân là 11, 7 là 111, 15 là 1111như vậy, bạn có ý tưởng. Bây giờ, điều gì xảy ra nếu bạn có &bất kỳ số nào so với một số chỉ bao gồm các số trong nhị phân? Hãy nói rằng chúng tôi làm điều này:

num & 7;

Nếu numnhỏ hơn hoặc bằng 7 thì kết quả sẽ là numdo mỗi bit &-ed với 1 là chính nó. Nếu numlớn hơn 7, trong quá trình &vận hành, máy tính sẽ xem xét các số 0 đứng đầu, tất nhiên sẽ vẫn là số không sau khi &hoạt động, phần duy nhất sẽ vẫn còn. Giống như trong trường hợp 9 & 7nhị phân, nó sẽ trông giống như

1001 & 0111

kết quả sẽ là 0001 là 1 trong số thập phân và xử lý phần tử thứ hai trong mảng.


Nhận xét của bạn nửa chừng văn bản nếu độ dài của mảng của bạn là lũy thừa 2 nên được đặt trong câu đầu tiên. Đó là một hạn chế rất nghiêm trọng để sử dụng thủ thuật này. Cá nhân tôi sẽ không thực hiện điều này dù sao, mã khó hiểu hơn so với phương pháp if hoặc mod .
Jan Doggen

@JanDoggen Bạn nói đúng, tôi sẽ đặt nó trong câu đầu tiên. Đối với mảng là sức mạnh của hai, theo kinh nghiệm của tôi đã có hơn vài lần khi nó hoạt động. Có lẽ bởi vì nó liên quan đến mạng và đồ họa.
dùng3552161

1
Điểm của bài đăng này là chỉ ra rằng các toán tử bitwise rất hữu ích để tạo ra các chuỗi số, chuỗi 0, 1, 2, 3, 0, 1, 2 ... chỉ là lần đầu tiên xuất hiện trong tâm trí.
dùng3552161

2

Tôi sử dụng chúng cho nhiều tùy chọn, theo cách này tôi chỉ lưu trữ một giá trị thay vì 10 hoặc nhiều hơn


2

nó cũng có thể có ích trong mô hình quan hệ sql, giả sử bạn có các bảng sau: BlogEntry, BlogC Category

theo truyền thống, bạn có thể tạo mối quan hệ nn giữa chúng bằng bảng BlogEntryC Category hoặc khi không có nhiều bản ghi BlogC Category bạn có thể sử dụng một giá trị trong BlogEntry để liên kết với nhiều bản ghi BlogCarget giống như bạn làm với các enum được gắn cờ, trong hầu hết RDBMS cũng có một toán tử rất nhanh để chọn trên cột 'được gắn cờ' đó ...


2

Khi bạn chỉ muốn thay đổi một số bit của Đầu ra của vi điều khiển, nhưng thanh ghi để ghi là một byte, bạn làm một cái gì đó như thế này (mã giả):

char newOut = OutRegister & 0b00011111 //clear 3 msb's
newOut = newOut | 0b10100000 //write '101' to the 3 msb's
OutRegister = newOut //Update Outputs

Tất nhiên, nhiều bộ vi điều khiển cho phép bạn thay đổi từng bit riêng lẻ ...


ngôn ngữ này được cho là gì?
Carson Myers

@Carson: Không có ngôn ngữ, đây là mã giả. Khi tôi thực sự đã làm điều đó một vài năm trước đây là hội, nhưng tôi cho rằng thật dễ dàng để làm điều đó trong C. Cảm ơn vì đã ngẩng cao đầu, tôi sẽ cập nhật để làm cho nó rõ ràng hơn
Emilio M Bumachar

Tôi đã chỉnh sửa câu trả lời để thay đổi các bình luận để việc tô sáng không bị sai lệch. Và tôi thấy, tôi nghĩ đó có thể là C nhưng bạn đã sử dụng 0b ... ký hiệu mà tôi muốn có sẵn trong C.
Carson Myers

2

Nếu bạn muốn tính mod số (%) của mình với công suất nhất định là 2, bạn có thể sử dụng yourNumber & 2^N-1, trong trường hợp này là giống như yourNumber % 2^N.

number % 16 = number & 15;
number % 128 = number & 127;

Điều này có lẽ chỉ hữu ích khi là một giải pháp thay thế cho hoạt động mô đun với cổ tức rất lớn là 2 ^ N ... Nhưng ngay cả khi đó tốc độ tăng tốc của nó đối với hoạt động mô đun là không đáng kể trong thử nghiệm của tôi trên .NET 2.0. Tôi nghi ngờ trình biên dịch hiện đại đã thực hiện tối ưu hóa như thế này. Có ai biết thêm về điều này không?


Trình biên dịch sử dụng tối ưu hóa này ... nhưng nếu bạn không biết về tối ưu hóa, bạn có thể không chọn được một ước số có công suất chính xác là 2.
Ben Voigt

Nó phụ thuộc vào tình hình. Trong C #, điều này thực sự tạo ra các kết quả khác nhau, cũng như %hoạt động còn lại, họ xử lý các tiêu cực khác nhau. Tuy nhiên, nếu bạn chuyển uintđến %, trình biên dịch C # sẽ thực sự tạo mã máy bằng bitwise AND khi đối số thứ hai là lũy thừa đã biết trước của hai.
Aaron Franke

1

Tôi đã thấy chúng được sử dụng trong các hệ thống kiểm soát truy cập dựa trên vai trò.


1

Có một thế giới thực sử dụng trong câu hỏi của tôi ở đây -
Chỉ trả lời thông báo WM_KEYDOWN đầu tiên?

Khi tiêu thụ một thông điệp WM_KEYDOWN trong windows C api bit 30 chỉ định trạng thái khóa trước đó. Giá trị là 1 nếu khóa bị tắt trước khi tin nhắn được gửi hoặc bằng 0 nếu khóa lên


1

Chúng chủ yếu được sử dụng cho các hoạt động bitwise (bất ngờ). Dưới đây là một vài ví dụ thực tế được tìm thấy trong cơ sở mã PHP.

Mã hóa ký tự:

if (s <= 0 && (c & ~MBFL_WCSPLANE_MASK) == MBFL_WCSPLANE_KOI8R) {

Cấu trúc dữ liệu:

ar_flags = other->ar_flags & ~SPL_ARRAY_INT_MASK;

Trình điều khiển cơ sở dữ liệu:

dbh->transaction_flags &= ~(PDO_TRANS_ACCESS_MODE^PDO_TRANS_READONLY);

Trình biên dịch thực hiện:

opline->extended_value = (opline->extended_value & ~ZEND_FETCH_CLASS_MASK) | ZEND_FETCH_CLASS_INTERFACE;

1

Bất cứ khi nào tôi mới bắt đầu lập trình C, tôi đều hiểu các bảng chân lý và tất cả những thứ đó, nhưng tôi không biết cách sử dụng nó cho đến khi tôi đọc bài viết này http://www.gamedev.net/reference/articles/article1563.asp (đưa ra ví dụ thực tế)


1
Không, nó không giống nhau. Trong C, nếu x == 1y == 2, sau đó x || yước lượng thành 1 và x | yước tính thành 0. Tôi cũng không thấy tại sao lại x^truevượt trội hơn !xbất kỳ cách nào. Nó gõ nhiều hơn, ít thành ngữ hơn và nếu xkhông xảy ra boolthì nó không đáng tin.
David Thornley

oh chờ đã .. vâng, điều đó thật ngu ngốc .. Tôi dường như không thể nghĩ thẳng ngày hôm nay.
Earlz

x | y ước tính thành 3 (chỉnh sửa: nvm, tôi thấy rằng bạn đang tham gia vào một cái gì đó được chỉnh sửa!)
Pod

1
@DavidThornley: Một trường hợp khi x^truevượt trội hơn !xsome->complicated().member->lookup ^= true; Không có phiên bản gán ghép của các toán tử đơn nguyên.
Ben Voigt

1

Tôi không nghĩ rằng điều này được tính là bitwise, nhưng mảng của ruby ​​xác định các hoạt động được thiết lập thông qua các toán tử bitwise thông thường. Vì vậy [1,2,4] & [1,2,3] # => [1,2]. Tương tự cho a ^ b #=> set differencea | b #=> union.


1

Giải pháp tuyến tính Tower Of Hà Nội sử dụng các hoạt động bitwise để giải quyết vấn đề.

public static void linear(char start, char temp, char end, int discs)
{
    int from,to;
    for (int i = 1; i < (1 << discs); i++) {
        from = (i & i-1) % 3;
        to = ((i | i-1) + 1) % 3;
        System.out.println(from+" => "+to);
    }
}

Giải thích cho giải pháp này có thể được tìm thấy ở đây

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.