Perl 28/13 ≈ 2.15
sub r{$s^=~($s^=$s/7215)<<8}
plik dziennika tutaj
Perl 29/13 ≈ 2.23
sub r{$s^=~($s^=$s<<8)/60757}
plik dziennika tutaj
Są to coś w rodzaju zmiany na Xorshift , z wykorzystaniem podziału zmiennoprzecinkowego zamiast przesunięcia w prawo. Obaj zdają 13 z 15 testów, nie zdają tylko testów 6 i 7.
Nie jestem do końca pewien, jak długi jest ten cykl, ale ponieważ poniższy kod nie kończy się w krótkim okresie czasu, prawdopodobnie jest to pełny 2 32 :
$start = r();
$i++ while $start != r();
print $i;
Perl 39/10 = 3,9
$s=$^T;sub r{~($s=$s*$s%4294969373)||r}
Uwaga: jeśli szukasz PRNG Blum-Blum-Shub-esque, rozwiązanie Keitha Randalla jest znacznie lepsze niż którekolwiek z nich.
Podobnie jak w przypadku mojego oryginalnego rozwiązania poniżej, jest to również implementacja Blum Blum Shub, z jedną zasadniczą różnicą. Korzystam z modułu nieco większego niż 2 32 ( M = 50971 • 84263 ), a gdy napotkamy wartość, że nie jest ona poprawną 32-bitową liczbą całkowitą (to znaczy większą niż 2 32 ), zwraca następną wartość w zamiast tego obrót. W gruncie rzeczy wartości te są przycinane, pozostawiając resztę obrotu niezakłóconą, co powoduje prawie równomierny rozkład.
Wydaje się, że to pomogło. Oprócz pozytywnego wyniku tych samych 9 testów, co teraz, w przekonujący sposób przechodzi również test minimalnej odległości. Przykładowy plik dziennika można znaleźć tutaj .
Perl 33/9 ≈ 3,67 (nieprawidłowy?)
$s=$^T;sub r{$s=$s*$s%4294951589}
Uwaga: to rozwiązanie może zostać uznane za nieprawidłowe, ponieważ najwyższe 0,00037% zakresu nigdy nie zostanie zaobserwowane.
Szybkie i brudne wdrożenie Blum Blum Shub . Zgłaszam następujące wyniki:
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
Przykładowy plik dziennika można znaleźć tutaj , możesz zakwestionować dowolny z wyników. Plik dla diehard można wygenerować w następujący sposób:
print pack('N', r()) for 1..4194304
a następnie potokowanie danych wyjściowych do pliku. Wygląda na to, że minimalna odległość minęła, ale jeśli uruchomisz ją wiele razy, zawsze będzie bardzo bliska 1,0 , co oznacza awarię.
Detale
Ogólnie rzecz biorąc, Blum Blum Shub jest strasznym PRNG, ale jego wydajność można poprawić, wybierając dobry moduł. M wybrałem to 7027 • 611207 . Oba te czynniki pierwsze, p i q , mają modułową resztę 3 (mod 4) i gcd (φ (p-1), φ (q-1)) = 2 , która jest tak niska, jak to tylko możliwe.
Chociaż są to jedyne kryteria wymienione na stronie wiki, nie wydaje się to wystarczające. Prawie wszystkie moduły, które wypróbowałem, nie zdały każdego testu. Ale jest garstka, która przejdzie niektóre testy, a ten, który wybrałem, wydaje się wyjątkowo dobry, z jakiegokolwiek powodu.
Podsumowując, sam test 5 wydaje się dość dobrym wskaźnikiem tego, jak dobry jest PRNG. Jeśli nie przejdzie prawie testu 5, reszta z nich wypadnie spektakularnie.
BONUS: Perl 62/14 ≈ 4,43
$t=$^T;sub r{$t|=(($s=$s/2|$t%2<<31)^($t/=2))<<31for 1..37;$t}
Tylko dla maniaków jest to 32-bitowa wersja PRNG wykorzystywana w oryginalnym Tetris dla NES. O dziwo, zdaje 14 z 15 testów!
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
Przykładowy plik dziennika może wcześniej tutaj .
Trzeba przyznać, że 1..37
bit nie jest dokładną transkrypcją. W wersji oryginalnej procedura entropii jest aktualizowana 60 razy na sekundę, a następnie sprawdzana w losowych odstępach czasu, w dużej mierze zależnych od danych wejściowych użytkownika. Dla każdego, kto chce zdemontować pamięć ROM, procedura entropii zaczyna się od 0xAB47
.
Pseudo-kod w stylu Python:
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