2013-04-29 3 views
10

Dla celów klasy programistycznej próbuję zilustrować słabości generatorów liczb losowych, które zwykle pochodzą ze standardowej biblioteki C, w szczególności "zły generator losowy" rand(), który pochodzi z OSX (quoth the manpage).W jaki sposób mogę sprawić, że OS RandX() nie przejdzie testu spektralnego?

Napisałem prosty program do testowania moje rozumienie widmowej testu:

#include <stdio.h> 
#include <stdlib.h> 

int main() { 
    int i; 
    int prev = rand(); 
    int new; 

    for (i=0; i<100000; i++) { 
    new = rand(); 
    printf("%d %d\n", prev, new); 
    prev = new; 
    } 
    return 0; 
} 

Ale kiedy wykreślić wynikowy rozrzutu, oto co mam:

Spectral test of OSX's rand()

bym spodziewałem się czegoś o większej strukturze, na przykład tego, co znajduje się on Wikipedia. Czy robię coś złego tutaj? Czy powinienem kreślić w większej ilości wymiarów?

UPDATE

Po sugestii PJS koszulka I zbliżeniu na części działki, gdzie liczby są mniejsze niż 1E7, i oto co znalazłem:

Spectral test of OSX's rand() limited to numbers smaller than 1e7

znajdę dokładnie te same linie pokazane przez pjs. Wydają się być pionowe, ale jest to niemożliwe, ponieważ oznaczałoby to, że niektóre wartości zostały "pominięte" przez rand(). Kiedy sort -n dane jest (próbka), co widzę:

571 9596797 
572 9613604 
575 9664025 
578 9714446 
580 9748060 
581 9764867 
584 9815288 
586 9848902 
587 9865709 
590 9916130 
592 9949744 
127774 13971 
127775 30778 
127780 114813 
127781 131620 
127782 148427 
127783 165234 
127785 198848 
127787 232462 
127788 249269 

Innymi słowy, punkty leżą na liniach, które są prawie, ale nie całkiem pionowe.

+0

Jeśli każde wejście jest losowa, to bym się spodziewać hałasu jak co otrzymał. Jeśli chcesz mieć uporządkowane dane wyjściowe, takie jak wyświetlane na połączonej stronie, dane losowe są prawdopodobnie _nie_, co chcesz. – SevenBits

+0

Tak, ale chodzi o to, że jest to próba wykazania, że ​​losowe dane nie są przypadkowe. Obraz wyświetlany na stronie linku ma być spisem stu tysięcy liczb losowych. (Jestem ciekawy, czy "każdy punkt reprezentuje 3 kolejne wartości pseudolosowe" oznacza, że ​​każde trzy liczby są używane jako współrzędne x, y, z punktu? –

+0

Myślę, że powinieneś wypróbować 3D. –

Odpowiedz

11

Liniowe generatory kongruencji wszystkie cierpią na problem zidentyfikowany przez George Marsaglia. "Twierdzenie Marsaglia" mówi, że k-krotki (wektory o długości k) spadną na ograniczoną liczbę hiperpłaszczyzn. Powiązanie to m**(1/k), gdzie k jest rozmiarem krotki, a m jest liczbą używaną dla modułu generatora. Tak więc, jeżeli moduł wynosi (2**31 - 1) i oglądasz zbiory 3, wykres 3-ci pokaże punkty spadające na nie więcej niż pierwiastek kostki z (2**31 - 1), lub około 1290 płaszczyzn, patrząc od prawej orientacji.

Wszystkie LCG podlegają Twierdzeniu Marsaglii. "Dobry" wykonuje się przy górnej granicy lub w jej pobliżu, a zły źle daleko od górnej granicy. To właśnie test spektralny skutecznie mierzy, i to właśnie widzieliście w linku do Wikipedii - RANDU, LCG z piekła rodem, produkuje trojaczki, które mieszczą się w zaledwie 15 płaszczyznach.

Generator biblioteki węglowej Apple używa 16807 jako mnożnika i (2**31 - 1) jako jego modułu. Jak idzie LCG, wcale nie jest tak źle. Dlatego twoja fabuła nie wykazała takich samych skrajności, jak RANDU. Jednak jeśli chcesz przyzwoitą jakość losowe numery nie używać LCG.

Uzupełnienie

Poszedłem do przodu i łukowaty miliard numery z funkcji Jabłko rand(), ale tylko te, gdzie drukowane obie wartości pary były mniej niż 2 miliony, czyli dolna lewy róg twojej działki. Oczywiście, padają na linie. Musisz tylko powiększyć, aby to zobaczyć z powodu gęstości linii.

Stary George był sprytnym facetem!

Marsaglia at work

+0

Dzięki! Trudno mi było zrozumieć, jak linie mogą być pionowe, ale potem "sortowałem" dane i stwierdziłem, że linie nie są w rzeczywistości idealnie pionowe, ale lekko przechylone. – lindelof

+0

Nie ma za co! Dobre wywołanie za pomocą 'sort -n'. Tak, linie wyglądają pionowo, dopóki nie uświadomisz sobie, że odstęp między "sąsiednimi" liniami wynosi ponad 100K, więc poziome przesunięcie o 100 lub nawet 1000 jest ledwo zauważalne. – pjs

3

Zakładając złe rand jest przystający generator liniowy, to znaczy, że to postać:

next = a * prev + b (mod RAND_MAX+1) 

można po prostu wziąć kilka terminów i rozwiązywać równania a i b. Po tym, powinieneś być w stanie wygenerować funkcję wyjścia tak, że struktura staje się łatwo widoczna.

Powiązane problemy