Bulmak için de Bruijn dizisini kullanarak


11

Sean Anderson yayınlanan bit kesmek twiddling bulmak için Eric Cole algoritmayı içeren log2v bir bölgesinin N bitlik tamsayıdır v içinde O(lg(N)) arama çarpma ile işlemleri.

Algoritma, De Bruijn dizisinden bir "sihirli" sayıya dayanır. Burada kullanılan dizinin temel matematik özelliklerini açıklayan var mı?

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
Fikir şu makaleden alınmıştır: supertech.csail.mit.edu/papers/debruijn.pdf . Boyut A de Brujn dizisi boyutu her bit dizeleri temsil etmek bir yoldur k çok kısaca: her olası dize bitişik altdizi tam olarak bir kez görünür. Eğer de Bruijn dizisini n 2 k bit kadar kaydırır ve son k bitlerini okursanız , n için benzersiz bir tanımlayıcıya sahip olursunuz . 2kkn2kkn
Sasho Nikolov

1
Bu arada bu sadece değerlerini hesaplar ; ve yazıldığı gibi sadece 32 bit tamsayılar için çalışır. log2v
Sasho Nikolov

1
@Sasho Bir cevaba mı dönüştünüz?
Yuval Filmus

@SashoNikolov Teşekkürler, soruya bir tavan fonksiyonu ekledi
Yury Bayda

Yanıtlar:


9

İlk not Bu algoritma sadece hesaplar olduğunu ve kod yazıldığı gibi, sadece çalışır v bir formunuzu 32 -bit kelime.log2vv32

İlk olarak görünen kayma ve / veya sekansları, önde gelen 1 bitini en az anlamlı bite kadar yayma işlevine sahiptir . Sayısal olarak, bu verir 2 log 2 v - 1 .v2log2v1

{0,1}s2kkXkk2iXii<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
    

Hızlı deneylere dayanan bazı gözlemler (umarım bunları doğru anladım):

  1. X tipi 65536 tamsayı vardır.

  2. X + Y tipi 4096 tamsayıları vardır. Bunlar tam olarak '0000 ...' dizisi ile başlayan X tipi tamsayılardır.

    • sezgi: baştaki sıfırlarla, döndürme = kaydırma?
  3. X + Y + Z tipi 256 tamsayı vardır. Bunlar tam olarak '0000011111 ...' dizisi ile başlayan X tipi tamsayılardır.

    • sezgi: ??
  4. Y tipi tüm tamsayılar da X tipindedir.

  5. Ancak, ne X tipi ne de Y tipi olmayan 768 tip Z tamsayısı vardır. Bunlar '1000011111 ...', '0111100000 ...' veya '1111100000 ...' ile başlar.


1
De Bruijn'in 2 ^ n-1 ile çarpımının neden sadece bir vardiya olan 2 ^ n'nin aksine çalıştığıyla ilgili tek cevap budur. Birisi yukarıdaki # 3 "sezgi" genişletmek eğer isterdim. Eric Cole bunu nasıl buldu? Deneme ve hata? Veya 2 ^ n-1 ile çarptığınızda bitlerin gerçekte ne olduğuna dair biraz anlayış?
FarmerBob

1
  • Bu sabit nereden geliyor?

Alıntı: "Mark Dickinson, 10 Aralık 2009 tarihinde, v'nin 2'nin gücü yerine 2'nin bir sonraki gücünden daha azına yuvarlanmasını gerektirerek birkaç işlemi tıraş etti". [Graphics.stanford.edu/~seander/bithacks.html]

Bu parçacıklı sabit, İkili alfabesi olan ama ekstra bir özelliğe sahip De Bruijn Dizisidir. Orijinal algoritma bu özel DB dizileri olmadan uygulanabildiğinden, ona 'Marc Dickinson Mülkü' diyeceğim. 2 ekstra işlem ekleyerek herhangi bir sıradan DB dizisi kullanabiliriz. Çalışma: v ^ = (v >> 1); // basamaklı veya vardiyadan sonra ayarlanmış MSB dışındaki tüm bitleri sil.

  • Sonuçlar (bruteforce)

Seq.Type | Hayır. Tamsayılar | Hayır. ile | Dönüşsüz | Property
B (2, 3) ile Konuş | 256 | 16 | 2 | 1
B (2, 4) | 64Ki | 256 | 16 | 4
B (2, 5) | 04Gi | 64Ki | 02Ki | 256
B (2, 6) | 16Ei | 04Gi | 64Mi | ??

  • Özel mülkiyet

0x7C4ACDD 2k1(mod232)2 k 132k1resim açıklamasını buraya girin2k - )1

  • Dickinson Property ile sözlükbilimsel olarak en küçük ikili de Bruijn dizileri

    [B (2,3): 0x1D] [B (2,4): 0x0F2D] [B (2,5): 0x7C4ACDD] [B (2,6): Hala Aranıyor]

Onları tanımlamak için zarif bir matematiksel formül veya bunları üretmek için teorem ya da benzer bir şey umuyorsanız, bunun sayı teorisine ve muhtemelen benim beceri setimin ötesindeki diğer alanlara derinlemesine bir bakış gerektireceğini düşünüyorum. Eğer vahşi bir tahminde bulunmam gerekirse, onlar selüral otomata tarafından üretilebilirler. Bu bir cevap değil neden? ancak neden çalıştığını ve neden düzgün çalıştığını sezgisel olarak anlamaya çalışmak, böylece güvenle kullanabilirsiniz.

PS: algoritmaların çalışma prensiplerini anlarsanız kolayca çıkarılan LUT yapısını kapsamadım.


Son olarak bulundu: B (2,6) 0x3f08a4c6acb9dbd - 'dickinson özelliği' ile 64bit de bruijn dizisi. En az 122K gibi bir dizi buldum.
FranG
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.