Diehard testlerinden geçen rastgele bir sayı üreteci oluşturun


50

Burada rastgelelikle ilgili birçok kod golf sorusu varken, henüz algoritmik bir sözde rasgele sayı üreteci yapmayı isteyen bir tane görmedim. Orada bu bir bit akışı oluşturmak ister ama o konuda sağlanan rasgelelik testler çok titiz değildi ve o kod golf değil.

Yazdığınız program, 0'dan 4294967295'e rasgele bir tamsayı döndürecek tek bir çağrılabilir fonksiyona sahip olacaktır. veya bir dilin yerleşik rand () kütüphanesi. Daha spesifik olarak, çalışmakta olduğunuz dilin aritmetik, dizi erişimi ve koşullu akış kontrolü ifadeleri gibi temel işleçleri ile sınırlıdır.

Programınızın puanı şu şekilde hesaplanır:

Score = C / R

C, koddaki karakterlerin uzunluğudur ve R, jeneratörünüzün geçtiği Diehard testlerinin sayısıdır (Rastgele sayı üreteciniz en az bir Diehard testini geçmezse, puanı sonsuzdur ve diskalifiye edilir). Oluşturduğunuz dosya, aralık boyunca eşit olarak dağılmış gibi görünen bir dizi P-değeri sağlarsa, jeneratörünüz bir Diehard testinden geçer [0, 1).

R'yi hesaplamak için, 16 MB'lık bir ikili veri dosyası oluşturmak için rastgele sayı üreticinizi varsayılan tohumuyla kullanın. İşlevin her çağrısı dört bayt döndürür; işleviniz bayt geri döndürmek için çok yavaşsa, bu, test etmenin ne kadar zor olduğuna bağlı olarak düşük bir puan almayı dengelemeye neden olur. Ardından, Diehard testlerinden geçirin ve verilen P değerlerini kontrol edin. (Bunları kendiniz uygulamaya çalışmayın; burada verilenleri kullanın )

Tabii ki en düşük puan kazanır.


İnternet bağlantısı gerektiren kodlara izin verilir mi? (çevrimiçi olarak herhangi bir rasgele işleve erişmeyecek, ancak belki de ping veya bir api çağrısının değerleri)
elssar

"Bu işlev, programın bir parçası olarak yazılmayan kitaplıkları veya diğer işlevleri çağırmamalıdır." Bu, İnternet bağlantısı işlevlerini içerir. Üretimin tamamen algoritmik olmalı.
Joe Z.

Diehard takımı 10-11 MB'lık girdi dosyaları bekliyor.
primo

Testlerle olan bağlantı kopmuş gibi görünüyor, işte olası bir alternatif.
2012rampampion

Bunu benim beyin-laf cevabım için nasıl yapmalıyım? Kodun pratik olamayacak kadar yavaş olduğunu düşünüyorum
Christopher

Yanıtlar:


6

Mathematica, 32/15 = 2.133

x=3;Mod[x=Mod[x^2,28!-67],2^32]&

BBS'nin basit bir uygulaması .

Ile oluşturulan ikili dosya:

f = %; (* assigns anonymous function declared in the previous expression to f *)
Export["random.bin", Array[f, 2^22], "UnsignedInteger32"];

Sonuçların özeti:

 1. BIRTHDAY SPACINGS TEST           .684805
 2. OVERLAPPING 5-PERMUTATION TEST   .757608/.455899
 3. BINARY RANK TEST                 .369264/.634256
 4. BINARY RANK TEST                 .838396
 5. THE BITSTREAM TEST                (no summary p-value)    
 6. OPSO, OQSO and DNA                (no summary p-value)
 7. COUNT-THE-1's TEST               .649382/.831761
 8. COUNT-THE-1's TEST                (no summary p-value)
 9. PARKING LOT TEST                 .266079
10. MINIMUM DISTANCE TEST            .493300
11. 3DSPHERES TEST                   .492809
12. SQEEZE                           .701241
13. OVERLAPPING SUMS test            .274531
14. RUNS test                        .074944/.396186/.825835/.742302
15. CRAPS TEST                       .403090/.403088/.277389

Tam random.binburada.

Tam günlük dosyası burada.


28!-67biraz yasaklayıcı. 64-bit bir tamsayıya uyacak daha küçük bir değer var mı?
primo

@primo Python gibi, Mathematica'nın tamsayıları varsayılan olarak isteğe bağlıdır, bu nedenle bir soruna neden olmaz.
2012rampampion

Özellikle C'ye taşınabilirlik için düşünüyordum
primo


21

Perl 28/13 ≈ 2,15

sub r{$s^=~($s^=$s/7215)<<8}

buraya günlük dosyası

Perl 29/13, 2.23

sub r{$s^=~($s^=$s<<8)/60757}

buraya günlük dosyası

Bunlar bir Xorshift'te , sağa kayma yerine kayan nokta bölmesini kullanan bir çeşitliliktir . Her ikisi de 15 testten 13'ünü geçiyor, sadece 6 ve 7 testlerini geçemiyor.

Ben döngüdür tam olarak ne kadar emin değilim, ancak aşağıdaki kod herhangi bir zaman kısa sürede sonlandırmak değil, bunun nedeni büyük olasılıkla dolu 2 32 :

$start = r();
$i++ while $start != r();
print $i;

Perl 39/10 = 3,9

$s=$^T;sub r{~($s=$s*$s%4294969373)||r}

Not: Bir Blum-Blum-Shub-esque PRNG arıyorsanız, Keith Randall'ın çözümü her ikisinden de çok daha iyi.

Aşağıdaki orijinal çözümümde olduğu gibi, bu da Blum Blum Shub'ın bir büyük fark yaratan uygulamasıdır. 2 32'den biraz daha büyük bir modül kullanıyorum ( M = 50971 • 84263 ) ve ne zaman bir değerin geçerli bir 32 bit tam sayı olmadığı (yani, 2 32'den büyük ) olmadığında bir sonraki değeri döndürür. bunun yerine döndürme. Esasında, bu değerler budanarak, rotasyonun geri kalanını rahatsız etmeden bırakarak neredeyse tekdüze bir dağılıma yol açar.

Yardım etmiş gibi görünüyor. Daha önce olduğu gibi aynı 9 testi geçmenin yanı sıra, şimdi inandırıcı bir şekilde Minimum Mesafe testini de geçiyor. Örnek bir günlük dosyası burada bulunabilir .


Perl 33/9 ≈ 3.67 (Geçersiz?)

 $s=$^T;sub r{$s=$s*$s%4294951589}

Not: Bu çözüm geçersiz sayılabilir, çünkü aralığın en yüksek% 0.00037'si asla gözlenmez.

Blum Blum Shub'ın hızlı ve kirli bir uygulaması . Aşağıdaki sonuçları talep ediyorum:

 1. passed - Birthday Spacings
 2. FAILED - Overlapping Permutations
 3. passed - Ranks of 31x31 and 32x32 Matrices
 4. passed - Ranks of 6x8 Matrices
 5. FAILED - Monkey Tests on 20-bit Words
 6. FAILED - Monkey Tests OPSO, OQSO, DNA
 7. FAILED - Count the 1s in a Stream of Bytes
 8. passed - Count the 1s for Specific Bytes
 9. passed - Parking Lot Test
10. FAILED - Minimum Distance Test
11. passed - Random Spheres Test
12. FAILED - The Squeeze Test
13. passed - Overlapping Sums Test
14. passed - Runs Test
15. passed - The Craps Test

Örnek bir günlük dosyası bulunabilir burada , sonuçların herhangi anlaşmazlığı çekinmeyin. Diehard dosyası aşağıdaki şekilde oluşturulabilir:

print pack('N', r()) for 1..4194304

ve ardından çıktının bir dosyaya aktarılması. Minimum Mesafe geçti gibi gözüküyor, ancak birden çok kez çalıştırırsanız her zaman 1.0'a çok yakındır , bu da başarısızlığı gösterir.


ayrıntılar

Genel olarak, Blum Blum Shub, korkunç bir PRNG'dir, ancak iyi bir modül seçerek performansı arttırılabilir. M benim seçimim olduğunu 611207 • 7027 . Bu asal faktörlerin her ikisi de, p ve q , modüler kalıntı 3 (mod 4) ve gcd (φ (p-1), φ (q-1)) = 2 olabilir;

Bunlar wiki sayfasında listelenen tek kriter olmasına rağmen, yeterli görünmüyor. Neredeyse denedim modulo her testi başarısız oldu. Ancak bazı testlerden geçecek bir avuç var ve seçtiğim sınavın ne sebeple olursa olsun son derece iyi olduğu görülüyor.

Son bir not olarak, Test 5 kendi başına PRNG'nin ne kadar iyi olduğunun oldukça iyi bir göstergesi gibi görünüyor. O olmazsa neredeyse Testi 5 geçmesi, bu olağanüstü geride kalanlarını başarısız olur.


BONUS: Perl 62/14, 4.43

$t=$^T;sub r{$t|=(($s=$s/2|$t%2<<31)^($t/=2))<<31for 1..37;$t}

Sadece geekery için, bu NES için orijinal Tetris'te kullanılan PRNG'nin 32-bit bir versiyonudur. Şaşırtıcı bir şekilde, 15 testten 14'ünü geçiyor!

 1. passed - Birthday Spacings
 2. passed - Overlapping Permutations
 3. passed - Ranks of 31x31 and 32x32 Matrices
 4. passed - Ranks for 6x8 Matrices
 5. passed - Monkey Tests on 20-bit Words
 6. passed - Monkey Tests OPSO, OQSO, DNA
 7. FAILED - Count the 1s in a Stream of Bytes
 8. passed - Count the 1s for Specific Bytes
 9. passed - Parking Lot Test
10. passed - Minimum Distance Test
11. passed - Random Spheres Test
12. passed - The Squeeze Test
13. passed - Overlapping Sums Test
14. passed - Runs Test
15. passed - The Craps Test

Örnek günlük dosyası önce can burada .

Kuşkusuz, 1..37bit kesin bir transkripsiyon değildir. Orijinal versiyonda, entropi rutini saniyede 60 kez güncellenir ve daha sonra büyük ölçüde kullanıcı girdisine bağlı olarak rasgele aralıklarla sorgulanır. ROM'u sökmeyi önemseyen herkes için entropi rutini başlar 0xAB47.

Python tarzı sahte kod:

carry = entropy_1 & 1
entropy_1 >>= 1
entropy_2 = (entropy_2 >> 1) | (carry << 31)
carry = (entropy_1 & 1) ^ (entropy_2 & 1)
entropy_1 |= carry << 31

Evet, algoritmanızın bit akımı testinde "başarısız" olduğunu fark ettim, ancak aslında 0.999999'un altında birkaç değere sahipti. Yine de, testleriniz doğru görünüyor.
Joe Z.

Yine de bir sorun var ve bu da 4294951589 ile 4294967295 arasındaki rakamların oluşma şansının bulunmamasına neden oluyor (sanırım bunun Diehard testlerinden bazılarında başarısız olmasının sebebinin bir parçası olmasına rağmen).
Joe Z.

1
@JoeZeng evet, bu bir problem. Test 5'de en belirgin olanıdır: ilk çalıştırmada 151k kelime eksik ve geri kalanında sadece 143k eksik kelime vardır. Bir çözüm, 2 ^ 32'den biraz daha büyük bir modül seçmek ve sıfıra sarılmayacak kadar büyük olan değerlere izin vermek olacaktır, ancak iyi çalışan bir tane bulamadım. Eğer yaparsam, yazıyı güncelleyeceğim.
primo

7

Python, 46/15 = 3.0666

v=3
def R():global v;v=v**3%(2**32-5);return v

Rasgelelik oluşturmak için modüler üstelemeyi kullanır. 2 ** 32-5, 2 ^ 32'den küçük en büyük asal sayıdır. (Test # 2'yi çalıştıramamakla aynı şey.)


Bir günlük dosyasını yapıştırabilir misiniz?
primo

Buraya giriş yapın: codepad.org/ZWhoGe0t
Keith Randall

1
Aptal Windows. Bu tüm kayıp dönüştürülmesi edildi \rve \niçin \r\ntabii ki sonuç eğriltir olan. Düzeltme, dosyayı doğrudan f = open('file.bin', 'wb')ve kullanarak yazmaktır f.write.
primo

Bu yeni puan önceki puanın altındadır, yani şimdi kabul edilen cevap.
Joe Z.

Bu yeni skor bir kez daha kesildi, bu yüzden kabul edilen cevabı değiştirdim.
Joe Z.

4

Ruby, 32/15 = 2.1333

Bu Keith Randall'ın Ruby'de uyguladığı çözümü.

$v=3;def R;$v=$v**3%(2**32-5)end

@JoeZ Bu, yepyeni Mathematica'nın cevabına bağlı olarak, en düşük cevap olarak görünüyor.
Riking

3

C # 144/15 = 9.6

uint a=15,b=26,y;uint q(int n){y=(a*1414549U+876619U)^(b*889453U+344753U);b=a;a=y>>12;return(a%256)<<n;}uint r(){return q(24)|q(16)|q(8)|q(0);}

Bu, tüm testleri geçti.

Çok fazla karakter olmadığında TestU01'i geçer.

Sonuç: http://codepad.org/iny6usjV

    uint a = 15;
    uint b = 26;

    byte prng8()
    {
        uint y = ((a * 1414549U + 876619U) ^ (b * 889453U + 344753U)) >> 12;
        b = a;
        a = y;
        return (byte)y;
    }

    uint prng32()
    {
        return ((uint)prng8() << 24) | ((uint)prng8() << 16) | ((uint)prng8() << 8) | (uint)prng8();
    }

2

C # - 103/14 = 7.36

double j=999;uint N(){uint i=0,n=0;for(;i++<4;n=n*256+(uint)j%256)for(j/=277;j<100000;j*=j);return n;}

Sonuçlar

Tüm test 6. dışında geçirir
de bakın sonuçlarına http://codepad.org/k1NSoyQW

açıklama

C # sadece her zamanki gibi netlik için Ruby ve Python ile rekabet edemez, ama denemekten zevk aldım. Kesinlikle aynı şekilde çalışacak başka değerler de var (yani, j = 999 için başlangıç ​​değeri ve bölen = 277). Bunları kısa bir deneyden sonra topladım.

Dosya oluşturma sarmalayıcı ile

class R
{
    public static void Main(string[] args)
    {
        var r = new R();
        using (var f = new System.IO.FileStream(".\\out.bin", System.IO.FileMode.Create, System.IO.FileAccess.Write, System.IO.FileShare.Read))
        using (var b = new System.IO.BinaryWriter(f))
        {
            for (long i = 0; i < 12 * 1024 * 1024; i += 4)
            {

                b.Write(r.N());
            }
        }
    }

    double j = 999;

    uint N()
    {
        uint i = 0, n = 0;
        for (; i++ < 4; n = n * 256 + (uint)j % 256)
            for (j /= 277; j < 100000; j *= j) ;
        return n;
    }

}

1

Python, 41/15 = 2.73333

v=0
def R():global v;v=hash(`v`);return v

Kinda kullanarak hile hash fonksiyonu dahili, ancak edilir yerleşik, bu nedenle gibi diğer yerleşikleri ile en fazla hile len. Kapak tarafında, global v;ifade için para ödemek zorunda kalıyorum

Tüm Diehard testlerini geçiyor (Test # 2 ile ilgili bir sorunum vardı, OSX makinemde SEGV var. Puanım için geçeceğini sanıyorum).

İşte 16MB dosyasını oluşturmak için bir sürücü:

import sys
for i in xrange(1<<22):
  r=R()
  sys.stdout.write('%c%c%c%c'%(r&255, r>>8&255, r>>16&255, r>>24&255))

"Bu işlev, programın bir parçası olarak da yazılmayan kitaplıkları veya diğer işlevleri çağırmamalı, özellikle / dev / random veya bir dilin yerleşik rand () kütüphanesini çağırmalıdır." Üzgünüm, ama bu girişinizi diskalifiye ediyor.
Joe Z.

Açıkçası, "len" de girişinizi diskalifiye eder.
Joe Z.

Çizgiyi nereye çekiyorsun? Yerleşik +bir işlev ve bu nedenle diskalifiye mi edilir?
Keith Randall

6
Ancak birçok dilde, operatörler ve fonksiyonlar aynıdır. Bkz +ve __add__python, veya operatör ++ c aşırı. Biliyorum, saçları bölüştüğümü biliyorum, bu yüzden bu örneği düşünün. Python'da böyle bir harita oluşturabilirsiniz: {'a':5}? Muhtemelen evet diyeceksiniz, ancak daha sonra hash('a')bunu yaparken kapakların altında çağrıldığını düşünün.
Keith Randall,

2
Sanırım bu şekilde işleve sözdizimsel olarak başvurmanız gerektiğinde çizgiyi çizerim. Python'da, harita adresine "hash" işlevine sözdizimiyle başvurmadan doğrudan erişmenize izin verecek bir hack bulabilirseniz kabul edebilirim.
Joe Z.

1

C, 38/15 = 2.533

long long x;f(){return(x+=x*x+9)>>32;}

Makinemde çalışan Diehard testlerini alamadım, ancak 8 GB'a kadar çıkan PractRand paketinden geçerek hepsini geçeceğini varsaydım.


0

Brain-Flak , 344 / (beklemede)

<>((()()){})<> push the amount of iterations to do for the PRNG
(((((((((((((((((((((((((((((((((((()()()){}()){})){}{}){()()()()({}[()])}{})){}{})){}{})()){}{})()){}{})){}{})){}{}){}())){}{})){}{})()){}{})()){}{})){}{})){}{})()){}{})()){}{}) push M (one of the values for the Blum Blum Shub PRNG
((((((((((((()()()){}){}){})){}{}){()({}[()])}{}){}())){}{})()){}{}) push s see above
<>{({}[()])<>starts the loop
(({({})({}[()])}{}) squares the current number
(<>))<>{(({})){({}[()])<>}{}}{}<>([{}()]({}))mods by M
<>}{}<>loop ends

Çevrimiçi deneyin!

Bu iyi çalışıyor ancak diehard testleri linkleri koptu :( yeni olanları alana kadar son bir puanım yok

Bu, Blum Blum Shub PRNG'yi kullandığı için çoğu vakayı geçmesi gerekir. Kullanılan sayılar yeterince büyüktür, 16 MB test senaryosunda hiçbir şablon görünmez


eğer bu geçersizse, bana söyle
Christopher

1
344'ü sayıyorum. Teorem: Tam olarak golf hiçbir Brain-flak programının tuhaf bayt sayısı yok.
user202729

0

Amaç-C, 40/1 = 40

Oldukça zekice bir yaklaşım, .hashburada biraz hile yapmak, ama hoşuma gitti

for(int v=9;v=@(v).hash;printf("%i",v));
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.