Tăng các bit 'mặt nạ'


80

Tôi hiện đang trong quá trình viết bảng điều tra cây, tôi gặp sự cố sau:

Tôi đang xem các bit có mặt nạ, tức là các bit trong đó các bit được đặt là một tập con của mặt nạ, tức là 0000101có mặt nạ 1010101. Những gì tôi muốn thực hiện là tăng bitet, nhưng chỉ đối với các bit bị che. Trong ví dụ này, kết quả sẽ là 0010000. Để làm cho nó rõ ràng hơn một chút, chỉ trích xuất các bit bị che, tức là 0011tăng chúng lên 0100và phân phối lại cho các bit mặt nạ, cho 0010000.

Có ai thấy cách hiệu quả để thực hiện việc này, không cần thực hiện thao tác bằng tay bằng cách sử dụng kết hợp các bitcans và mặt nạ tiền tố?

Câu trả lời:


123

Chỉ cần điền vào các bit không phải mặt nạ với các bit để chúng truyền đi mang theo:

// increments x on bits belonging to mask
x = ((x | ~mask) + 1) & mask;

11
Đó là một mẹo hay ... Gần như phép thuật mà tôi đã nói là không có :)
Eugene Sh.

8
@EugeneSh. Đừng bao giờ tin rằng nó không phải như vậy.
zch

23
Có lẽ không quan trọng đối với OP vì họ đã chấp nhận, nhưng có lẽ cần lưu ý rằng điều này sẽ bằng không các bit không phải mặt nạ. Nếu họ bị cần thiết ở những nơi khác, bạn phải cẩn thận hơn thay thế x. Có thể x = (x & ~mask) | (((x | ~mask) + 1) & mask);.
TripeHound

2
@TripeHound Nếu chúng không cần thiết, bạn thậm chí sử dụng một chút mặt nạ sẽ có ích gì?
someonewithpc

1
@someonewithpc Không chắc bạn đang cố gắng nói / hỏi gì. Tôi không biết tại sao OP cần tăng một tập hợp các bit không liền kề, vì vậy tôi không biết liệu các bit khác trong giá trị ban đầu có quan trọng hay không. Ví dụ: nếu giá trị ban đầu là 0101101(ví dụ: .1.1.0.trong các bit không có mặt nạ và 0.0.1.1trong "bộ đếm") thì chúng có cần 0111000 (một "bộ đếm" mới 0.1.0.0trong khi bảo toàn .1.1.0.) hay chỉ 0010000được chấp nhận. Câu trả lời này (và có thể là những câu khác, mặc dù tôi chưa kiểm tra) đưa ra câu trả lời sau; phiên bản của tôi sẽ cung cấp cho phiên bản cũ nếu đó là những gì được yêu cầu.
TripeHound

20

Mặc dù không trực quan so với câu trả lời được chấp nhận, nhưng điều này chỉ hoạt động trong 3 bước:

x = -(x ^ mask) & mask;

Điều này có thể được xác minh theo đề xuất của zch:

  -(x ^ mask)
= ~(x ^ mask) + 1  // assuming 2's complement
= (x ^ ~mask) + 1
= (x | ~mask) + 1  // since x and ~mask have disjoint set bits

Sau đó, nó trở thành tương đương với câu trả lời được chấp nhận.


2
Câu trả lời của zch rất trực quan, mình có thể thấy ngay là đúng vì anh ấy giải thích rõ ràng. Logic của câu trả lời này là gì? Công thức này thực hiện như thế nào để mang lại hiệu quả như mong muốn? Tôi tò mò về quá trình khám phá, bản chất của cái nhìn sâu sắc ở đây.
FooF

Tôi nghĩ rằng việc xác minh của bạn sẽ đơn giản hơn nhiều nếu bạn chỉ chứng minh rằng -(x ^ mask) == (x | ~mask) + 1bất cứ khi nào x là một tập con của mặt nạ và sau đó tham chiếu đến câu trả lời của tôi.
zch

5
-(x^mask) == ~((x ^ mask) - 1) == ~(x ^ mask) + 1 == (x ^ ~mask) + 1 == (x | ~mask) + 1. Phương trình cuối cùng đúng bởi vì các tập bit là rời rạc, các tập khác luôn đúng (ít nhất là trong phần bù 2).
zch

1
Những ai tò mò về các bước tôi đã thực hiện để tìm ra câu trả lời này có thể tham khảo trang này .
nglee

5
Có thể đáng để chỉ ra rằng những thứ này không tối ưu hóa giống nhau, điều này thường liên quan đến những người làm việc xoay vòng bit: godbolt.org/g/7VWXas - mặc dù cái nào thực sự ngắn hơn dường như phụ thuộc vào trình biên dịch. Không biết cái nào sẽ nhanh hơn hoặc nếu sự khác biệt là đáng kể.
Leushenko

7

Nếu thứ tự lặp lại không quá quan trọng và một phép toán giảm dần sẽ đáp ứng nhu cầu của bạn, bạn chỉ có thể sử dụng hai phép toán:

Hãy bắt đầu với

x = mask

và nhận giá trị trước đó với

x = (x - 1) & mask

x - 1phần thay đổi bit khác không cuối cùng thành 0 và đặt tất cả các bit ít quan trọng hơn thành 1. Sau đó, & maskmột phần chỉ để lại các bit mặt nạ trong số đó.


2 hoạt động, tốt đẹp. Tuy nhiên, tôi tranh luận rằng đó là cùng một cách tiếp cận, chỉ tuyên truyền sự vay mượn thông qua các số không, thay vì truyền qua các số không.
zch

@zch, đúng rồi, cảm ơn. Tôi sẽ diễn đạt lại câu trả lời
DAle

chỉ hoạt động nếu x bắt đầu với tất cả các bit không phải mặt nạ rõ ràng.
Jasen

@Jasen, chắc chắn. Nhưng không khó để thiết lập các bit không phải mặt nạ đó. Và các câu trả lời khác có vấn đề tương tự.
DAle
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.