Tam olarak n set bitli sayılar üretmek için PRNG


12

Şu anda ikili veri oluşturmak için bazı kod yazıyorum. Özellikle belirli bir sayıda set bit ile 64-bit sayılar oluşturmak gerekir; daha kesin olarak, prosedür almalı ve tam olarak bit olarak ve geri kalanı 0 olarak ayarlanmış bir sahte rasgele 64 bit sayı döndürmelidir .n 10<n<64n1

Mevcut yaklaşımım şöyle bir şey içeriyor:

  1. Yalancı 64 bitlik bir sayı .k
  2. Sonucu saklayarak bitleri cinsinden sayın .bkb
  3. Eğer , çıkış ; aksi takdirde 1'e gidin.kb=nk

Bu işe yarıyor, ama yetersiz görünüyor. Bundan daha zarif set biti ile sayı üretebilen bir çeşit PRNG algoritması var mı?n

Yanıtlar:


12

İhtiyacınız olan şey, 0 ile arasında rastgele bir sayıdır . O zaman sorun bunu bit desenine dönüştürmektir.(64n)1

Bu numaralandırma kodlaması olarak bilinir ve en eski konuşlandırılmış sıkıştırma algoritmalarından biridir. Muhtemelen en basit algoritma Thomas Cover'dan. Basit bitlere dayanarak, bit uzunluğunda bir kelimeniz varsa , set bitlerinin en anlamlı bit sırasında olduğu durumlarda, bu kelimenin bu özelliğe sahip tüm kelimelerin sözlükbilimsel sıralamasındaki konumu dır-dir:x kx 1nxkx1

1ik(xii)

Örneğin, 7 bitlik bir kelime için:

i(0001011)= ( 3

ben(0000111)=(23)+(12)+(01)=0
i(0001101)= ( 3
i(0001011)=(33)+(12)+(01)=1
i(0001101)=(33)+(22)+(01)=2

...ve bunun gibi.

Bit desenini sıradan almak için, sırayla her bitin kodunu çözersiniz. C benzeri bir dilde böyle bir şey:

uint64_t decode(uint64_t ones, uint64_t ordinal)
{
    uint64_t bits = 0;
    for (uint64_t bit = 63; ones > 0; --bit)
    {
        uint64_t nCk = choose(bit, ones);
        if (ordinal >= nCk)
        {
            ordinal -= nCk;
            bits |= 1 << bit;
            --ones;
        }
    }
    return bits;
}

Sadece 64'e kadar binom katsayılarına ihtiyacınız olduğundan, bunları önceden hesaplayabileceğinizi unutmayın.


  • Cover, T., Sayımsal Kaynak Kodlama . Bilgi Kuramı Üzerine IEEE İşlemleri, Cilt IT-19, Sayı 1, Ocak 1973.

Güzel ve zarif! Sayımsal kodlama çok faydalı bir şeye benziyor - üzerinde iyi kaynaklar var mı (tercihen ders kitabı formunda)?
Koz Ross

Bu aslında pratikte daha iyi performans sağlıyor mu? (Elbette bu, RNG'nin hızına bağlıdır.) Değilse, daha karmaşık kod kullanmanın bir anlamı yoktur.
Gilles 'SO- kötü olmayı bırak'

1
@Giles Bunu cs.se olduğu için bir bilgisayar bilimi sorusu olarak yorumladım. Ben bir RRR dizi uygulama etrafında yalan oldu çünkü sadece kaynak kodu verdi. (Bunun ne anlama geldiğinin açıklaması için bkz. Alexbowe.com/rrr .)
Takma

1
@Gilles Sorunuzu takip etmek için, hem saf yöntemimi hem de Pseudonym tarafından sağlanan yöntemi uyguladım. Naif yöntem, çok basit bir xorshift PRNG kullanırken bile , Pseudonym'in yöntemi neredeyse anlık iken, sayı başına 20 saniyelik bir şey aldı . Bunun için önceden hesaplanmış binom tabloları kullandım.
Koz Ross

1
@KozRoss n bit sayıları üretir ve k bitleri ayarlanmış sayıları ararsanız, k n / 2'den uzaksa, bunlar oldukça nadir olur; bunu açıklar.
gnasher729

3

Başka yollarla elde edilen Pseudonym cevabına çok benzer.

Toplam kullanılabilir kombinasyon sayısına yıldızlar ve çubuklar yöntemi ile ulaşılabilir , bu nedenle . Numaranızı örneklemeye çalışacağınız toplam 64 bit sayı sayısı, bundan çok daha fazla olacaktır.c=(64n)

Ne o zaman gerek, bir rastgele sayı sizi yol açabilir bir işlevdir arasında değişen için tekabül 64 bit kombinasyonu.1 ck1c

Pascal'ın üçgeni size bu konuda yardımcı olabilir, çünkü her düğümün değeri tam olarak bu düğümden üçgenin köküne giden yol sayısını temsil eder ve tüm sola dönüşler varsa, aradığınız dizelerden birini temsil etmek için her yol yapılabilir ile etiketlenir ve her sağa ile döner .010

Öyleyse , belirlenecek kalan bit sayısı ve , kullanılacak kalan bit sayısı olsun.yxy

Olduğunu biliyoruz , ve uygun bir şekilde bir numaranın bir sonraki bit belirlemek için kullanabilir her adımda:(xy)=(x-1y)+(x-1y-1)

whbenlex>0

benfx>y

benfk>(x-1y):ss+"1",kk-(x-1y),yy-1

else:ss+"0"

else:ss+"1",yy-1

xx-1


2

Oldukça zarif bir başka yöntem ise, bu yığın akışı cevabında açıklandığı gibi biseksiyonu kullanmaktır . Buradaki fikir, biri en fazla k bitinin ayarlandığı ve birinin en az k bitinin ayarlandığı bilinen iki kelimeyi saklamak ve bunlardan birini tam olarak k bitlerine doğru hareket ettirmek için rasgelelik kullanmaktır. İşte bunu gösteren bazı kaynak kodu:

word randomKBits(int k) {
    word min = 0;
    word max = word(~word(0)); // all 1s
    int n = 0;
    while (n != k) {
        word x = randomWord();
        x = min | (x & max);
        n = popcount(x);
        if (n > k)
            max = x;
        else
            min = x;
    }
    return min;
}

Çeşitli yöntemlerin performans karşılaştırmasını yaptım ve k çok küçük olduğu bilinmedikçe bu genellikle en hızlı olanıdır.


0

Aşağıdakileri yapabilirsiniz:

1) Rasgele sayı üretin, ile arasında .1 64k164

2) ila ila arasını ayarlayın .0 1k01

3) tekrar aşama 1 ve 2 keren

64 0bir[] , saniyenin tümü ile bit dizidir640

for(i=1 to n)
{
    k=ran(1,65-i) % random number between 1 and 65-i
    for(x=1;x<65;x++)
    {
        if(A[x]==0)k--;
        if(k==0)break;
    }
    A[x]=1;
}

Nesir kodunuzla eşleşmiyor mu? Kod asla 1diziye s atamaz . Ayrıca, çoklu ks çarpıştığında tekdüze bir dağılım oluşturmuyor (hatta kısıtlamaları karşılayan sayılar bile değil)
Bergi

@ Bergi Ya satırını unuttum ... şimdi ekledi. Ve birden fazla k çarpışması ele alınır. Bkz. İlk sayı 1 ile 64 arasında, ikincisi 1 ile "kalan" 63 arasında seçilir. Böylece sayım sırasında 1'i atlar ... bkz.hat. Ve tekdüze dağılımdır. i f ( A [ X ] = = 0 ) k - - ;bir[x]=1benf(bir[x]==0)k--;
Kullanıcı Bulunamadı

Ah, şimdi görüyorum. Düzyazı algoritması atlamadan bahsetmedi.
Bergi

@ArghyaChakraborty Orada 1 tabanlı indeksleme mi kullanıyorsunuz?
Koz Ross

@KozRoss (tabii ki tamamen sıfır olacaktır) ile ne olacağıyla başlayın. Bu nedenle, değerini kontrol eder ve k - anlamı eldeki bu da verir . Böylece, değerini döngünün dışında ayarlar . Yani evet 1 tabanlı indeksleme. 0 dayalı yapmanız gereken tüm iç değiştirecek yapmak içinben=1,k=1birbir[1]==0truek--;k=0bir[1]=1fÖr(x=0;x<64;x++)
Not Found Kullanıcı
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.