(Tamamen deterministik) sözde bit akımı üretme


11

Elleriniz bağlıyken Rastgele esinlenerek :


Amaç

Bu zorluğun amacı, tamamen rasgele görünen, ancak aslında deterministik bir şekilde üretilen 1s ve 0s dizesi olan bir psödondom bit akışı üreten bir program yazmaktır. Programınız 1 ve 0'lık bir dize (isteğe bağlı boşlukla) çıkarmalı ve aşağıdaki gereksinimleri sağlamalıdır:

  1. Sınırsız zaman ve bellek verildiğinde, programınız sonsuza kadar 1s ve 0s dize çıkarmaya devam etmelidir.
  2. Programınız makul bir makinede yaklaşık bir dakika içinde 1000'den fazla rastgele bit çıkarmalıdır. Bu gereklilik mümkün değilse, o zaman azaltacağım.
  3. Bit dizisi tekrarlanabilir, ancak yinelenen bölümün uzunluğu 1000 bit'ten fazla olmalıdır.
  4. Bit dizisi mümkün olduğunca çok sayıda rastgele testten (aşağıda açıklanmıştır) geçmelidir.
  5. Program herhangi bir harici kaynaktan herhangi bir girdi almamalı veya yerleşik rand () benzeri bir işlev kullanmamalıdır.
  6. Yukarıdaki gereksinim nedeniyle, program her çalıştırıldığında aynı tam bit dizesini çıktılamalıdır.

Rasgelelik Testi # 1

Sahte sözde bit dizisi görsel inceleme sonrasında belirgin bir model içermemelidir.

Rasgelelik Testi # 2 (yorumlara göre değişebilir)

Bit dizesi 1s ve 0s arasında eşit bir dağılım içermelidir. Bunu (ve diğer şeyleri de) test etmek için bit akışı, 3 bit uzunluğundaki segmentlere ayrılır 101|111|001.

Tüm bu segmentlerden 1 / 8'inin üç 1'i ve 0'ı olmamalı, 3/8'inin iki 1'i olmalı ve bir 0, 3/8'inin 1 ve iki 0'ı ve 1/8'i olmalıdır bunların 1'i ve üç 0'ı olmamalıdır.

Rasgelelik Testi # 3

"Run", hepsi aynı değere sahip ardışık bir bit dizisi olarak tanımlanır. Dize 1001001110, 1 ( 1..1.....0) boyutunda üç çalışma, 2 ( .00.00....) boyutunda iki çalışma ve 3 ( ......111.) boyutunda bir çalışma içerir . Çalışanların örtüşmediğine dikkat edin.

1000 rasgele bitlik bir dizeden, yaklaşık 1 boyutta 250 çalışma, 2 boyutunda 125 çalışma, 3 boyutunda 62 çalışma vb. Olmalıdır. Genel olarak, R çalışma boyutu için 1000/(2**(R+1)), bu boyutta yaklaşık çalışma olmalıdır .

Rasgelelik Testi # 4

İlk 840 bit, her biri 420 bitlik iki yarıya bölünür. İlk yarıdaki her bit, ikinci yarıdaki karşılık gelen bit ile karşılaştırılır. İki bit, zamanın yüzde elli kadarıyla eşleşmelidir.


İşte bir Perl programının kaynak kodu şimdi gerçekleştirdiği testler 2 ile 4. olarak, bit dizisi herhangi beyazboşluk gerektirir olmasıdır.


Objektif Kazanan Ölçüt Zamanı!

Kazanan, 6 gereksinimin tümünü ve tüm rasgelelik testlerini, rastgelelikten ayırt edilemeyecek derecede geçiren programdır. Birden fazla program bunu başarırsa, tekrarlanması en uzun süreyi alan program kazanacaktır. Birden fazla program bunu başarırsa, o zaman kravat kırıcı gibi davranmak için daha fazla rasgelelik testi bulmam gerekebilir.


# 2 ve # 3 rasgelelik için gerçekten çok iyi kriterler değil. Özellikle # 2 için, rastgele bir örnek muhtemelen bu özelliği göstermeyecektir. Belki daha büyük bir örnek boyutu yapabilirsiniz? 100 ile 300 arasında bir şey öneririm.
Joel Cornett

Daha iyi bir ölçüm yöntemi hareketli bir ortalama olacaktır, çünkü bit akışındaki büyük bir pencerede ortalama çok fazla değişmeyecektir (ve yaklaşık 0.5 olmalıdır)
Joel Cornett

@JoelCornett Tavsiye için teşekkürler. Rasgelelik testleri hakkında fazla bir şey bilmiyorum. # 2'yi başka bir şeye değiştireceğim ve hareketli ortalamaları okuyorum.
PhiNotPi

1
Sorun değil. Rastgele diziler kümelenme eğilimindedir ve eşit olarak dağılmaz, bu bazen sahtekarlığı tespit etmek için muhasebede kullanılır. (Sahte numaralar genellikle çok eşit olarak dağıtılacaktır, çünkü onları icat eden insanlar rastgelelik için tekdüzelikle hata
yaparlar

Yerleşik kripto işlevlerini (AES veya SHA-2 gibi) kullanabilir miyim?
CodesInChaos

Yanıtlar:


8

C, 61

main(s,n){for(n=1u<<31;putchar((s%=n)/(n/2)&1|48);s*=65539);}

Evet, bunun kod golfü olmadığını biliyorum. Bu açıkça bir anti-çözüm ... ama elbette kriterlerinizi yeterince yerine getiriyor.

dışarı | kafa -c840
$ ./a.out | kafa -c840 | perl tester.pl
Test 2: 1 (1) 2.93333333333333 (3) 3.1 (3) 0.966666666666667 (1)
Test 3: 214 99 71 24 7 5 1 1 2 2
Test 4: 0.495238095238095

Süre uzunluğu 2²⁹'dir.


6
Bu, var olan en kötü rasgele sayı üreticilerinden biri olarak bilinen yaygın bir şeyden rasgeleliği anlatmanın ne kadar zor olduğunu gösterir. +1.
PhiNotPi

8

Mathematica 78 53 karakter

Pi'nin ikili temsilinin rakamları, kanıtlanmamış olmasına rağmen düzensizce üretilmiş gibi davranıyor gibi görünüyor.

Aşağıdaki basit rutin, dondalık basamaklara karşılık gelen pi'nin ikili basamaklarını belirleyici olarak dize olarak döndürür :

f[d_]:=ToString@FromDigits@RealDigits[N[Pi,d],2][[1]]

kullanım

Pi'nin 301 ondalık basamağının karşılığını talep edersek, 1000 ikili basamak alırız.

f[301]
StringLength[%]

(* out *)
1100100100001111110110101010001000100001011010001100001000110100110001001100011001100010100010111000000011011100000111001101000100101001000000100100111000001000100010100110011111001100011101000000001000001011101111101010011000111011000100111001101100100010010100010100101000001000011110011000111000110100000001001101110111101111100101010001100110110011110011010011101001000011000110110011000000101011000010100110110111110010010111110001010000110111010011111110000100110101011011010110110101010001110000100100010111100100100001011011010101110110011000100101111001111110110001101111010001001100010000101110100110100110001101111110110101101011000010111111111101011100101101101111010000000110101101111110110111101110001110000110101111111011010110101000100110011111101001011010111010011111001001000001000101111100010010110001111111100110010010010010100001100110010100011110110011100100010110110011110111000010000000000111110010111000101000010110001110111111000001011001100011011010010010000011011000011100011

1000 (* characters *)

Pi irrasyonel bir sayı olduğu için nokta yoktur. Bununla birlikte, çalışan donanım nedeniyle pratik kısıtlamalar olacaktır.

Test 1 Bana iyi geliyor.

Test 2

d=301;
Partition[RealDigits[N[Pi,d],2][[1]],{3}];
Tally[%]
(* out *)
{{{1,1,0},35},{{0,1,0},45},{{0,0,0},41},{{1,1,1},40},
{{0,1,1},50},{{1,0,1},32},{{1,0,0},43},{{0,0,1},47}}

Daha ayrıntılı kontrol:

d=10^6;
Partition[RealDigits[N[Pi,d],2][[1]],{3}];
Tally[%]

{{{1,1,0},138565},{{0,1,0},138146},{{0,0,0},138260},{{1,1,1},138427},
{{0,1,1},139119}, {{1,0,1},138404},{{1,0,0},137926},{{0,0,1},138462}}

Test 3: Çalışmalar

d=10^6;
res3=SortBy[Tally@Split@RealDigits[N[Pi,d],2][[1]],Last]/.{a_,b_}:> {Length[a],b}
ListPlot[res3 ,AxesLabel-> {"Run Length","Runs"},AxesOrigin->{0,0}]

Çalışmaların dağılımını sistematik olarak kontrol etmek için çok sayıda vaka çalıştırdım. Yaklaşık 3 milyon ikili basamakta, 830k koşu 1, 416k koşu 2, 208k koşu 3, 104k koşu 4, vb.

çalışır 2 Test 4: Verilerin birinci ve ikinci yarısının eşleştirilmesi

Karşılaşmalar 212 0 ve 2 vakadır; uyumsuzluklar, ilgili basamakların toplamının 1 olduğu 208 vakadır.

d=301;
Tally[Plus@@Partition[Take[RealDigits[N[Pi,d],2][[1]],840],420]]

(* out *)
{{1,208},{0,108},{2,104}}

Zamanlama

3321928 ikili rakamı (10 ^ 6 ondalık basamağa karşılık gelen) hesaplamak iki saniyenin altında sürer.

(r=f[10^6]);//AbsoluteTiming
StringLength[r]

(*out*)
{1.785928,Null}    
3321928

1
Birinin bunu yapacağını biliyordum ...
Counterclockwis açmak için durdu

1
Düşük asılı meyve, değil mi?
DavidC

Bir bayt kaydetmek eyerine kullanamaz pimısınız?
pppery

edüzensizce dağıtılır?
DavidC

3

Python, 90

g=[19]
print(''.join("01"[(g.append((11*g[-1]+13)%1024)or g[-1])>512]for i in range(1000)))

gtohum değeridir. Rastgele örnekleme, örnek araçların tekrarlanan rastgele örneklemesinin ortalama 0.506ve aa standart sapmasını .0473(1000 örnek büyüklüğü) verdi. Ne yazık ki, rastgelelik ilk tohuma oldukça duyarlıdır. Yukarıdaki koddaki tohum bana en iyi rasgeleliği verdi: p

GÜNCELLEME

Bu kodun OP testlerine nasıl uyduğunu görelim:

Test # 1

Bu biraz öznel ... ama benim için oldukça düzensiz görünüyor.

Test # 2

Üç 1'ler: 0.141
İki 1'ler : 0.371
Bir 1: 0.353
Sıfır 1'ler : 0.135

Test # 3

Boyuta göre çalışır:

8: 11
7: 3
6: 7
5: 13
4: 32
3: 67
2: 119
1: 216

Test # 4

Eşitlik oranı: 0.94 Bu bir yazım hatasıdır. Yakında doğru numarayla güncellenir.


1
'For' dan önce boşlukları kaldırabilirsiniz.
daniero

2

Haskell 74 58

main=print$iterate(read.take 9.show.(^3))7>>=show.(`mod`2)

Sadeleştirme için shiona teşekkürler . Sonuçlar:

/ pseudorandom | kafa -c 1000

./pseudorandom | kafa -c 1000 | perl test.pl

Test 2: 0.966666666666667 (1) 2,4 (3) 3,3 (3) 1.33333333333333 (1)

Test 3: 260108 66 33 15 11 5 2

Test 4: 0.495238095238095

Bu aynı zamanda korkunç bir sahte rastgele jeneratör (von-Neuman tarafından kullanılana benzer). Farkında olmayanlar concatMap == (=<<) == flip . (>>=)için (listeler için)


Sen yerini alabilir \x->if odd x then"1"else"0"ile show.(`mod`2).
shiona

1

Soru esasen "bir akış şifresi uygulamak" ile eşdeğerdir. RC4 uyguluyorum, çünkü nispeten basit.

Hiçbir anahtar kullanmıyorum ve ilk 100000 biti düşürüyorum, çünkü RC4'ün başlangıcı biraz önyargılı, özellikle de anahtar programı atladığımdan beri. Ama testinizi bu olmadan bile geçmesini beklerdim (20 karakterlik kod tasarrufu).

Normalde bir döngü başına tam bir bayt çıktı olurdu, ancak C # içinde ikili dönüştürmek oldukça çirkin, bu yüzden sadece en az anlamlı bit dışında her şeyi atıyorum.

var s=Enumerable.Range(0,256).ToArray();
byte i=0,j=0;
for(int k=0;;k++)
{
    i++;
    j+=(byte)s[i];
    var t=s[i];s[i]=s[j];s[j]=t;
    if(k>99999)
        Console.Write(s[i]+s[j]&1);
}

Veya boşluk bırakmadan:

var s=Enumerable.Range(0,256).ToArray();byte i=0,j=0;for(int k=0;;k++){i++;j+=(byte)s[i];var t=s[i];s[i]=s[j];s[j]=t;if(k>99999)Console.Write(s[i]+s[j]&1);}

C #, 156 karakter, LinqPad deyim modunda çalışır. Tam bir C # programı için normal boyler plakasını ekleyin.


Ayrıca yerleşik kripto ilkelleri de kullanabiliriz (Cheater çözümü):

var h=SHA256.Create();for(BigInteger i=0;;i++){Console.Write(h.ComputeHash(i.ToByteArray())[0]%2);}

(C #, 99 karakter, LinqPad'ın ifade modunda çalışır. Normal C # derleyicisi için biraz kazan plakası eklemeniz gerekir)

Kriptografik karma işlevlerinin çıktısı rastgele verilerden ayırt edilemeyecek şekilde tasarlanmıştır, bu yüzden ona attığınız tüm rastgele testlerden (daha zor öl, ...) geçmesini beklerim, ama test etmek için çok tembelim.


1

C, 52 karakter

main(a){for(a=1;putchar(48+a%2);a=a/2^-(a%2)&576);}

Bu 10 bit LFSR, test sonuçlarıdır:

$ ./a.out |head -c 1000 | perl randtest.pl
Test 2: 1.13333333333333 (1) 2.86666666666667 (3) 3.16666666666667 (3) 0.833333333333333 (1)
Test 3:  251 122 64 32 16 8 4 2  1
Test 4: 0.466666666666667

a1 olarak başlamalıdır (argüman olmadan çağrıldığı varsayılarak). Ayrıca sopa olabilir a=, ortada böyle bir şey a=a/2^-!putchar(49-a%2)%576(algoritması ile bazı özgürlükler alarak)
Walpen

@walpen: İlk uygulamam ayarlanmadı a, " The program must not take any input from any external sources" nedeniyle değiştirdim
Hasturkun

1

Adaçayı / Python

Bu program, 3 3 3 3 formunun yeterince uzun üs alma kulelerinde ortak olan en sağdaki ikili rakamları basar . . . Mümkün olduğunca üretilebilecek her şey için, bunlar Graham'ın sayısının en sağdaki ikili rakamlarıdır . Rakam dizisi sonsuzdur ve periyodik değildir.

m = 1; x = 3; last = 0
while True:
    m *= 2; x = pow(3,x,m); l = len(bin(x))
    print '1' if l > last else '0',
    last = l

1000 basamak için bu işlem 2 saniyeden az sürdü; ancak, zaman basamak sayısından doğrusal olarak çok daha hızlı artacaktır.

OP programını kullanarak test sonuçları vardır

Test 2: 1.26666666666667 (1) 3.16666666666667 (3) 2.8 (3) 0.766666666666667 (1)
Test 3:  268 126 61 30 20 7 2  1 1
Test 4: 0.466666666666667

( 32000'den fazla basamak ve ek istatistiksel testler için bkz . G'nin en sağ basamakları rastgele mi?


1

Java, 371 317

128 bit göre LFSR (bit musluklar vardır Xilinx uygulama Not 52 )

EDIT: BigInteger kullanarak memnun değildi, bu yüzden bu sürümü değil. Bazı karakterler kaydedildi. İyi bir 'tohumlama' yöntemi düşünemediğim için çıktı biraz daha az rastgele olabilir.

Yeni Kod: Bağımsız Değişkenler: BITS_TO_PRINT

class R{public static void main(String[]a){int L=65536;int[]v={0,128,126,101,99};int[]b=new int[L];for(int x=0;x<L;x++)b[x]=(x*x)&1;for(int i=0;i<Integer.parseInt(a[0])+L;i++){if(1!=(b[v[1]]^b[v[2]]^b[v[3]]^b[v[4]]))b[v[0]]=1;else b[v[0]]=0;if(i>L)System.out.print(b[v[0]]);for(int j=0;j<5;j++)v[j]=(v[j]-1)&(L-1);}}}

Eski Sürüm: Bağımsız Değişkenler: SEED, BITS_TO_PRINT

import java.math.BigInteger;class R{public static void main(String[]a){BigInteger v=new BigInteger(a[0]);BigInteger m=new BigInteger("ffffffffffffffffffffffffffffffff",16);for(int i=Integer.parseInt(a[1]);i>0;i--){v=v.shiftLeft(1);if(!(v.testBit(128)^v.testBit(126)^v.testBit(101)^v.testBit(99))){v=v.setBit(0);}v=v.and(m);java.lang.System.out.print(v.testBit(0)?1:0);}}}

Yeni Sürüm: Örnek çıktı, bitler = 100:

011001100111000110010100100111011100100111000111001111110110001001100000100111111010111001100100011

1
BTW, bu yazıdaki her iki Noah hesabının da aynı kişi olduğunu varsayıyorum. Öyleyse, bir moderatörden meta.codegolf.stackexchange.com
Peter Taylor

0

JavaScript - 1000 sahte rasgele bit için 1ms ila 2ms (100000 bit için 139ms ila 153ms)

Bu çözüm, kare köklerin irrasyonel olduğu ve dolayısıyla hemen hemen rastgele olduğu gerçeğini kullanır. Temel olarak, başlamak için 2'nin kare kökünü alır, ikiliye dönüştürür, önceki kökle eşleşen önde gelen kısmı atar, rastgele dizeye ekler, bir sonraki daha yüksek sayı ile tekrar eder (veya tekrarlanan sayı 2'ye geri döner) ve en az 30 bit uzunluğundaydı) ve rastgele dizeyi yeterince uzun olduğunda döndürür.

var getDeterministicPseudoRandString = function(length){
    var randString = '';

    var i = 2;
    var prevRand = '';

    outerLoop:
    while(randString.length < length){
        var nextRand, nextFullRand = Math.sqrt(i++).toString(2).substring(1).replace('.', '');
        nextRand = nextFullRand;
        for(var j = prevRand.length; j > 0; j--){
            var replaceString = prevRand.substring(0, j);

            nextRand = nextFullRand;

            if(nextFullRand.indexOf(replaceString) == 0){
                if(j == prevRand.length && j > 30){
                    //start i over at 2
                    console.log('max i reached: ' + i);

                    i = 2;
                    continue outerLoop;
                } else {
                    nextRand = nextFullRand.replace(replaceString, '');
                }

                break;
            }
        }
        prevRand = nextFullRand;

        randString += nextRand;
    }

    return randString.substring(0, length);//Return the substring with the appropriate length
};

Henüz testlerden geçmedim, ama bunların üzerinde iyi olacağını hayal ediyorum. İşte bir keman, böylece eylem halinde görebilirsiniz. Zamanlarım için programı birkaç kez çalıştırdım ve aralıklar olarak en hızlı ve en yavaş değerleri aldım.


0

piton

import hashlib
x=''
while 1:
    h=hashlib.sha512()
    h.update(x)
    x=h.digest()
    print ord(x[0])%2

Yaklaşık 2 ^ 512'lik bir süreye sahip olmalıdır.


0

perl, 44 bayt

Bu kod golf değil biliyorum, ama ben her zaman basit bir ikinci dereceden fonksiyonun düşük dereceli bit alarak hayranıyım, örneğin:

$x=1/7;print substr($x*=4-4*$x,9,1)%2while 1

Süre 3 milyardan fazla, ama daha fazla hesaplamak için disk alanım tükendi.


1
sayısal sabitleri ve anahtar kelimeleri bir araya getirerek ve ayrıca 4 dağıtarak 3 karakter kaydedebilirsiniz:$x=1/7;print substr($x*=4-4*$x,9,1)%2while 1
ardnew
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.