Perl 28/13 ≈ 2,15
sub r{$s^=~($s^=$s/7215)<<8}
файл журнала здесь
Perl 29/13 ≈ 2,23
sub r{$s^=~($s^=$s<<8)/60757}
файл журнала здесь
Это что-то вроде вариации Xorshift , использующего деление с плавающей точкой вместо правого смещения. Они оба проходят 13 из 15 тестов, не пройдя только тесты 6 и 7.
Я точно не знаю , как долго этот цикл, а потому , что следующий код не прекращается в любой короткий промежуток времени, то, скорее всего , полный 2 32 :
$start = r();
$i++ while $start != r();
print $i;
Perl 39/10 = 3,9
$s=$^T;sub r{~($s=$s*$s%4294969373)||r}
Примечание: если вы ищете PRNG от Blum-Blum-Shub-esque, решение Кейта Рэндалла намного лучше, чем любой из них.
Как и в моем исходном решении ниже, это также реализация Blum Blum Shub, с одним существенным отличием. Я использую модуль, немного больший чем 2 32 ( M = 50971 • 84263 ), и всякий раз, когда встречается значение, которое не является действительным 32-битным целым числом (то есть больше 2 32 ), оно возвращает следующее значение в вращение вместо. По сути, эти значения сокращаются, оставляя остальную часть вращения без помех, что приводит к почти равномерному распределению.
Кажется, это помогло. Помимо прохождения тех же 9 тестов, что и раньше, теперь он также убедительно проходит тест на минимальное расстояние. Пример файла журнала можно найти здесь .
Perl 33/9 ≈ 3,67 (неверно?)
$s=$^T;sub r{$s=$s*$s%4294951589}
Примечание: это решение может считаться недействительным, поскольку самый верхний 0,00037% диапазона никогда не будет наблюдаться.
Быстрая и грязная реализация Blum Blum Shub . Я требую следующие результаты:
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
Пример файла журнала можно найти здесь , не стесняйтесь оспаривать любой из результатов. Файл для diehard может быть сгенерирован следующим образом:
print pack('N', r()) for 1..4194304
и затем скопировать вывод в файл. Минимальное расстояние выглядит так, как будто оно прошло, но если вы запускаете его несколько раз, оно всегда очень близко к 1,0 , что указывает на сбой.
подробности
В общем, Blum Blum Shub - ужасный PRNG, но его производительность можно улучшить, выбрав хороший модуль. M Я выбрал это 7027 • 611207 . Оба из этих простых факторов, p и q , имеют модульный остаток 3 (mod 4) , и gcd (φ (p-1), φ (q-1)) = 2 , что является настолько низким, насколько это возможно.
Хотя это единственные критерии, перечисленные на вики-странице, этого недостаточно. Почти все по модулю, которые я попробовал, провалились в каждом тесте. Но есть горстка, которая пройдет некоторые тесты, и тот, который я выбрал, кажется исключительно хорошим по любой причине.
В заключение отметим, что тест 5 сам по себе является довольно хорошим показателем того, насколько хорош PRNG. Если он почти не пройдет 5-й тест, он остальным провалится.
БОНУС: Perl 62/14 ≈ 4.43
$t=$^T;sub r{$t|=(($s=$s/2|$t%2<<31)^($t/=2))<<31for 1..37;$t}
Просто для гиков: это 32-битная версия PRNG, использованная в оригинальном Tetris для NES. Удивительно, но он проходит 14 из 15 тестов!
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
Пример файла журнала можно раньше здесь .
По общему признанию, 1..37
бит не является точной транскрипцией. В оригинальной версии процедура энтропии обновляется 60 раз в секунду, а затем запрашивается через случайные интервалы, в значительной степени зависящие от пользовательского ввода. Для тех, кто хочет разобрать ROM, процедура энтропии начинается с 0xAB47
.
Псевдокод в стиле 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