Menggunakan urutan de Bruijn untuk menemukan

11

Sean Anderson menerbitkan bit twiddling hacks yang berisi algoritma Eric Cole untuk menemukan dari integer bit dalam operasi dengan operasi multiply dan lookup.N v O ( lg ( N ) )catatan2vNvHAI(lg(N))

Algoritme bergantung pada nomor "ajaib" dari urutan De Bruijn. Adakah yang bisa menjelaskan sifat matematika dasar dari urutan yang digunakan di sini?

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];
Yury Bayda
sumber
2
Idenya berasal dari makalah ini supertech.csail.mit.edu/papers/debruijn.pdf . Urutan de Brujn dari ukuran adalah cara untuk mewakili semua string bit dari ukuran k dengan sangat ringkas: setiap string yang mungkin muncul tepat sekali sebagai urutan berikutnya. Jadi jika Anda menggeser urutan de Bruijn dengan n 2 k bit dan membaca bit k terakhir , Anda memiliki pengidentifikasi unik untuk n . 2kkn2kkn
Sasho Nikolov
1
Ngomong-ngomong ini hanya menghitung ; dan seperti yang tertulis itu hanya berfungsi untuk bilangan bulat 32-bit. log2v
Sasho Nikolov
1
@ Sasho Berubah menjadi jawaban?
Yuval Filmus
@SashoNikolov Terima kasih, menambahkan fungsi plafon pada pertanyaan
Yury Bayda

Jawaban:

9

Perhatikan pertama bahwa algoritma ini hanya menghitung , dan ketika kode ditulis, ia hanya bekerja untuk v yang sesuai dengan kata 32- bit.catatan2vv32

Urutan pergeseran dan atau -s yang muncul pertama memiliki fungsi menyebarkan 1-bit terkemuka semua jalan ke bit paling tidak signifikan. Secara numerik, ini memberi Anda 2 log 2 v - 1 .v2catatan2v-1

Bagian yang menarik adalah trik de Bruijn, yang berasal dari makalah Leiserson, Prokop, dan Randall ini (tampaknya para profesor MIT menghabiskan waktu melakukan sedikit peretasan :)). Yang perlu Anda ketahui tentang urutan de Bruijn adalah bahwa mereka mewakili semua urutan yang mungkin dari panjang tertentu dengan cara yang dikompresi mungkin. Tepatnya, urutan de Brujn di atas alfabet adalah string biner dengan panjang 2 k sehingga setiap panjang k string biner muncul tepat sekali sebagai substring yang bersebelahan (pembungkus diijinkan). Alasan ini berguna adalah jika Anda memiliki angka X{0,1}s2kkXrepresentasi bit yang merupakan urutan de Bruijn (diisi dengan nol), maka bit k atas dari 2 i X secara unik mengidentifikasi i (selama i < k ).kk2sayaXsayasaya<k

Sasho Nikolov
sumber
3
Perhatikan bahwa Anda dapat menggunakan urutan de Bruijn dengan cara ini untuk menghitung diberikan 2 i . Namun, Anda tidak dapat menggunakan urutan de Bruijn sembarang untuk menghitung i diberikan 2 i - 1 . Di sini 0x07C4ACDD = 00000111110001001010110011011101 tampaknya menjadi urutan de Bruijn dengan beberapa properti tambahan, berkat tambahan - 1 tidak merusak pendekatan ini. saya2sayasaya2saya-1-1
Jukka Suomela
Terima kasih @JukkaSuomela, saya agak bingung tentang itu. Saya kira Anda selalu bisa menambahkan 1 ke . v
Sasho Nikolov
5

Beberapa komentar (bukan jawaban). Mari kita mengklasifikasikan integer 32-bit sebagai berikut:c

  • Tipe X: (sebagai string biner) adalah urutan De Bruijn (untuk semua rotasi, bit [27,31] berbeda). Sebuah contoh:c

    11111011100110101100010100100000
    
  • Ketik Y: bit [27,31] dari yang berbeda untuk saya = 0 , 1 , .2ic . Inilah yangLeiserson et al. menggunakan. Contoh:i=0,1,...,31

    00000100011001010011101011011111
    00001111101110011010110001010010
    
  • Ketik Z: bit [27,31] dari berbeda untuk i = 0 , 1 ,(2saya+1-1)c . Inilah yang kita butuhkan dalam pertanyaan awal. Contoh:saya=0,1,...,31

    00000111110001001010110011011101  (07C4ACDD)
    10000111110001001010110011011101
    01111000001110110101001100100011
    11111000001110110101001100100011
    

Beberapa pengamatan berdasarkan eksperimen cepat (saya harap ini benar):

  1. Ada 65536 bilangan bulat tipe X.

  2. Ada 4096 bilangan bulat tipe X + Y. Inilah bilangan bulat tipe X yang dimulai dengan urutan '0000 ...'

    • intuisi: dengan nol nol di depan, rotasi = bergeser?
  3. Ada 256 bilangan bulat tipe X + Y + Z. Inilah bilangan bulat tipe X yang dimulai dengan urutan '0000011111 ...'

    • intuisi: ??
  4. Semua bilangan bulat dari tipe Y juga dari tipe X.

  5. Namun, ada juga 768 bilangan bulat tipe Z yang bukan tipe X atau tipe Y. Ini dimulai dengan '1000011111 ...', '0111100000 ...', atau '1111100000 ...'

Jukka Suomela
sumber
1
Ini adalah satu-satunya jawaban yang berhubungan dengan mengapa penggandaan De Bruijn dengan 2 ^ n-1 bekerja, berlawanan dengan 2 ^ n, yang hanya merupakan perubahan. Saya akan senang jika seseorang dapat memperluas "intuisi" # 3 di atas. Bagaimana Eric Cole muncul dengan ini? Percobaan dan kesalahan? Atau beberapa pemahaman tentang apa yang sebenarnya terjadi pada bit ketika Anda kalikan dengan 2 ^ n-1?
FarmerBob
1
  • Dari mana konstanta ini berasal?

Mengutip: "Pada 10 Desember 2009, Mark Dickinson memotong beberapa operasi dengan mengharuskan v dibulatkan menjadi satu kurang dari kekuatan 2 berikutnya daripada kekuatan 2". [graphics.stanford.edu/~seander/bithacks.html]

Konstanta partikel ini adalah Urutan De Bruijn dengan alfabet Biner tetapi dengan properti tambahan. Saya akan menyebutnya 'Properti Marc Dickinson' karena algoritma asli dapat diimplementasikan tanpa urutan DB khusus ini. Dengan menambahkan 2 operasi tambahan kita bisa menggunakan urutan DB biasa. Operasi: v ^ = (v >> 1); // clr semua bit kecuali MSB yang diatur setelah cascading atau-shift.

  • Hasil (bruteforce)

Seq.Type | Tidak. Integer | Tidak. DBSeq. dengan | tanpa Rotasi | dengan Dickinson Property
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 | ??

  • Properti spesial

0x7C4SEBUAHCDD 2k1(mod232)32k1masukkan deskripsi gambar di sini2k1

  • Urutan de Bruijn biner terkecil secara leksikografis dengan Dickinson Property

    [B (2,3): 0x1D] [B (2,4): 0x0F2D] [B (2,5): 0x7C4ACDD] [B (2,6): Masih Mencari]

Jika Anda berharap untuk rumus matematika yang elegan untuk menggambarkan mereka atau teorema untuk menghasilkan mereka atau sesuatu yang serupa, saya pikir ini akan membutuhkan wawasan mendalam tentang teori bilangan dan mungkin bidang lain yang berada di luar keahlian saya. Jika saya di mana membuat tebakan liar saya harus bertaruh mereka bisa diproduksi oleh automata seluler. Ini bukan jawaban kenapa? pada dasar yang keras tetapi upaya untuk secara intuitif memahami mengapa ia bekerja dan mengapa itu bekerja dengan baik, sehingga Anda dapat menggunakannya dengan percaya diri.

PS Saya tidak membahas konstruksi LUT, yang mudah disimpulkan jika Anda memahami prinsip kerja algoritma.

FranG
sumber
Akhirnya ditemukan: B (2,6) 0x3f08a4c6acb9dbd - urutan 64bit de bruijn dengan 'properti dickinson'. Saya telah menemukan setidaknya 122K urutan seperti itu.
FranG