Sử dụng chuỗi de Bruijn để tìm


11

Sean Anderson xuất bản chút twiddling hacks chứa thuật toán của Eric Cole để tìm ra log2v của một N bit số nguyên v trong O(lg(N)) hoạt động với nhân và tra cứu.

Thuật toán dựa trên một số "ma thuật" từ chuỗi De Bruijn. Bất cứ ai có thể giải thích các thuộc tính toán học cơ bản của chuỗi được sử dụng ở đây?

uint32_t v; // find the log base 2 of 32-bit v
int r;      // result goes here

static const int MultiplyDeBruijnBitPosition[32] = 
{
  0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30,
  8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31
};

v |= v >> 1; // first round down to one less than a power of 2 
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;

r = MultiplyDeBruijnBitPosition[(uint32_t)(v * 0x07C4ACDDU) >> 27];

2
Ý tưởng xuất phát từ bài báo này supertech.csail.mit.edu/ con / debruijn.pdf . Chuỗi de Brujn có kích thước là một cách để biểu diễn tất cả các chuỗi bit có kích thước k rất chính xác: mỗi chuỗi có thể xuất hiện chính xác một lần như là một chuỗi liền kề. Vì vậy, nếu bạn dịch chuyển chuỗi de Bruijn theo n 2 k bit và đọc hết các bit k cuối cùng , bạn có một mã định danh duy nhất cho n . 2kkn2kkn
Sasho Nikolov

1
Bằng cách này chỉ tính này ; và như đã viết, nó chỉ hoạt động cho các số nguyên 32 bit. log2v
Sasho Nikolov

1
@Sasho Biến thành câu trả lời?
Yuval Filmus

@SashoNikolov Cảm ơn, đã thêm chức năng trần cho câu hỏi
Yury Bayda

Câu trả lời:


9

Lưu ý đầu tiên mà thuật toán này chỉ tính , và là mã được viết, nó chỉ hoạt động cho v mà vừa vào 32 chữ -bit.log2vv32

Chuỗi các ca và or-s xuất hiện đầu tiên có chức năng truyền 1 bit hàng đầu của xuống tận bit quan trọng nhất. Số lượng, điều này mang đến cho bạn 2 log 2 v - 1 .v2log2v1

{0,1}s2kkXcó biểu diễn bit là một chuỗi de Bruijn (được đệm bằng số 0), sau đó các bit k trên cùng của 2 i X xác định duy nhất i (miễn là i < k ).kk2iXii<k


3
i2ii2i11

v

5

c

  • c

    11111011100110101100010100100000
    
  • 2ici=0,1,...,31

    00000100011001010011101011011111
    00001111101110011010110001010010
    
  • (2i+11)ci=0,1,...,31

    00000111110001001010110011011101  (07C4ACDD)
    10000111110001001010110011011101
    01111000001110110101001100100011
    11111000001110110101001100100011
    

Một số quan sát dựa trên các thử nghiệm nhanh (tôi hy vọng tôi hiểu đúng):

  1. Có 65536 số nguyên loại X.

  2. Có 4096 số nguyên loại X + Y. Đây chính xác là những số nguyên loại X bắt đầu bằng dãy '0000 ...'

    • trực giác: với các số 0 đứng đầu, xoay = dịch chuyển?
  3. Có 256 số nguyên loại X + Y + Z. Đây chính xác là những số nguyên loại X bắt đầu bằng dãy '0000011111 ...'

    • trực giác: ??
  4. Tất cả các số nguyên loại Y cũng thuộc loại X.

  5. Tuy nhiên, cũng có 768 số nguyên loại Z không phải loại X cũng không phải loại Y. Chúng bắt đầu bằng '1000011111 ...', '0111100000 ...' hoặc '1111100000 ...'


1
Đây là câu trả lời duy nhất liên quan đến lý do tại sao phép nhân De Bruijn với 2 ^ n-1 hoạt động, trái ngược với 2 ^ n, đó chỉ là một sự thay đổi. Tôi rất thích nếu ai đó có thể mở rộng dựa trên "trực giác" của # 3 ở trên. Làm thế nào mà Eric Cole nghĩ ra điều này? Phep thử va lôi sai? Hoặc một số hiểu biết về những gì thực sự xảy ra với các bit khi bạn nhân với 2 ^ n-1?
Nông dânBob

1
  • Trường hợp này liên tục đến từ đâu?

Trích dẫn: "Vào ngày 10 tháng 12 năm 2009, Mark Dickinson đã loại bỏ một vài thao tác bằng cách yêu cầu v được làm tròn xuống ít hơn một so với sức mạnh tiếp theo là 2 thay vì sức mạnh của 2". [Graphics.stanford.edu/~seander/bithacks.html]

Hằng số hạt này là một chuỗi De Bruijn với bảng chữ cái nhị phân nhưng có một thuộc tính bổ sung. Tôi sẽ gọi nó là 'Tài sản Marc Dickinson' vì thuật toán ban đầu có thể được thực hiện mà không cần các chuỗi DB đặc biệt này. Bằng cách nối thêm 2 thao tác, chúng ta có thể sử dụng bất kỳ chuỗi DB thông thường nào. Hoạt động: v ^ = (v >> 1); // clr tất cả các bit ngoại trừ MSB được đặt sau khi xếp tầng hoặc dịch chuyển.

  • Kết quả (bruteforce)

Seq.Type | Số nguyên | Số DBSeq. với | không có phép quay | với tài sản Dickinson
B (2, 3) | 256 | 16 | 2 | 1
B (2, 4) | 64Ki | 256 | 16 | 4
B (2, 5) | 04Gi | 64Ki | 02Ki | 256
B (2, 6) | 16Ei | 04Gi | 64Mi | ??

  • Tài sản đặc biệt

0x7C4ACDD 2k1(mod232)32k1nhập mô tả hình ảnh ở đây2k1

  • Trình tự nhị phân de Bruijn nhị phân nhỏ nhất với Dickinson Property

    [B (2,3): 0x1D] [B (2,4): 0x0F2D] [B (2,5): 0x7C4ACDD] [B (2,6): Vẫn đang tìm kiếm]

Nếu bạn đang hy vọng một công thức toán học tao nhã để mô tả chúng hoặc định lý để tạo ra chúng hoặc một cái gì đó tương tự, tôi nghĩ rằng điều này sẽ đòi hỏi cái nhìn sâu sắc về lý thuyết số và có thể các lĩnh vực khác nằm ngoài kỹ năng của tôi. Nếu tôi đoán một cách hoang dã thì tôi cá là họ có thể được sản xuất bởi automata di động. Đây không phải là một câu trả lời tại sao? trên cơ sở nghiêm ngặt nhưng cố gắng hiểu trực giác tại sao nó hoạt động và tại sao nó hoạt động tốt, vì vậy bạn có thể tự tin sử dụng nó.

PS Tôi không bao gồm việc xây dựng LUT, điều này dễ dàng được suy luận nếu bạn hiểu các nguyên tắc làm việc của các thuật toán.


Cuối cùng tìm thấy: B (2,6) 0x3f08a4c6acb9dbd - một chuỗi 64 bit de bruijn với 'thuộc tính Dickinson'. Tôi đã tìm thấy ít nhất 122K một chuỗi như vậy.
FranG
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.