Вдохновленный Рэндом со связанными руками :
Цель
Цель этой задачи - написать программу, которая генерирует псевдослучайный поток битов, который представляет собой строку из 1 и 0, которая выглядит чисто случайной, но фактически генерируется детерминированным способом. Ваша программа должна вывести строку из 1 и 0 (с необязательным пробелом) и должна соответствовать следующим требованиям:
- Учитывая неограниченное время и память, ваша программа должна продолжать выводить строки 1 и 0 навсегда
- Ваша программа должна вывести более 1000 случайных битов за одну минуту на приемлемой машине. Если это требование невозможно, я уменьшу его.
- Строка битов может повторяться, но длина повторяющейся секции должна быть больше 1000 бит.
- Строка битов должна пройти как можно больше тестов случайности (описанных ниже).
- Программа не должна принимать какие-либо входные данные от каких-либо внешних источников или использовать какую-либо встроенную функцию rand ().
- Из-за вышеуказанного требования программа должна выводить одну и ту же строку битов при каждом запуске.
Тест случайности № 1
Строка псевдослучайных битов не должна содержать какой-либо очевидной картины при визуальном осмотре.
Тест на случайность # 2 (возможны изменения в зависимости от комментариев)
Строка битов должна содержать равное распределение 1 и 0. Чтобы проверить это (и другие вещи), поток битов разбивается на сегменты длиной 3 бита, например 101|111|001
.
Из всех этих сегментов 1/8 из них должны иметь три единицы и не иметь нулей, 3/8 из них должны иметь две единицы и одну цифру 0, 3/8 из них должны иметь одну 1 и две цифры 0 и 1/8 из них не должно быть 1 и три 0.
Тест случайности № 3
«Выполнение» определяется как последовательный ряд битов, которые имеют одинаковое значение. Строка 1001001110
имеет три цикла размера 1 ( 1..1.....0
), два цикла размера 2 ( .00.00....
) и один цикл размера 3 ( ......111.
). Обратите внимание, что пробеги не перекрываются.
Из строки из 1000 случайных битов должно быть около 250 прогонов с размером 1, 125 прогонов с размером 2, 62 прогона с размером 3 и т. Д. В целом, для 1000/(2**(R+1))
прогонов размера R должно быть около прогонов такого размера.
Тест случайности № 4
Первые 840 бит разделены на две половины по 420 бит каждая. Каждый бит в первой половине сравнивается с соответствующим битом во второй половине. Два бита должны совпадать примерно в пятидесяти процентах случаев.
Вот исходный код программы на Perl, которая выполняет тесты со 2 по 4. На данный момент требуется, чтобы строка битов не содержала пробелов.
Объективный критерий времени победы!
Победителем становится программа, которая проходит все 6 требований и все тесты на случайность до такой степени, что она неотличима от случайности. Если несколько программ выполнят это, то выиграет та, которая повторяется дольше всех. Если несколько программ выполнят это, то мне, возможно, придется найти больше тестов случайности, чтобы действовать в качестве тай-брейков.
источник
Ответы:
С, 61
Да, я знаю, что это не код гольф. Это, очевидно, скорее антирешение ... но оно вполне соответствует вашим критериям.
Продолжительность периода 2²⁹.
источник
Mathematica
7853 символовЦифры двоичного представления числа Пи, кажется, ведут себя так, как будто они хаотически получены, хотя это не доказано.
Следующая простая процедура детерминистически возвращает в виде строки двоичные цифры числа pi, соответствующие
d
десятичным цифрам:использование
Если мы запрашиваем аналог 301 десятичного знака числа Пи, мы получаем 1000 двоичных знаков.
Поскольку Pi - иррациональное число, периода нет. Тем не менее, будут практические ограничения из-за аппаратного обеспечения.
Тест 1 выглядит хорошо для меня.
Тест 2
Более тщательная проверка:
Тест 3: Запуски
Я провел большое количество случаев, чтобы систематически проверять распределение прогонов. Примерно в 3 миллионах двоичных разрядов было 830 тыс. Циклов из 1, 416 тыс. Циклов из 2, 208 тыс. Циклов из 3, 104 тыс. Циклов из 4 и т. Д.
Тест 4: сопоставление первой и второй половины данных
Матчи - это 212 случаев 0 и 2; несоответствия - это 208 случаев, когда сумма соответствующих цифр равна 1.
тайминг
Для вычисления 3321928 двоичных цифр требуется менее двух секунд (что соответствует 10 ^ 6 десятичным цифрам).
источник
e
вместо того,pi
чтобы сохранить один байт?e
распределены хаотично?Питон, 90
g
это начальное значение. Случайная выборка демонстрирует удивительно нормальное распределение, повторная случайная выборка средних значений выборки дает среднее значение0.506
и стандартное отклонение.0473
(размер выборки 1000). К сожалению, случайность очень чувствительна к начальному семени. Семя в приведенном выше коде дало мне лучшую случайность: pОБНОВИТЬ
Давайте посмотрим, как этот код выдерживает тесты OP:
Тест № 1
Это немного субъективно ... но для меня это выглядит нерегулярно.
Тест № 2
Тест № 3
Работает по размеру:
Тест № 4
источник
Haskell
7458Спасибо Шиону за упрощение. Результаты:
Это также ужасный псевдослучайный генератор (похожий на тот, который использовал фон Нейман). Для тех, кто не знал
concatMap == (=<<) == flip . (>>=)
(для списков)источник
\x->if odd x then"1"else"0"
наshow.(`mod`2)
.Вопрос по сути эквивалентен «реализовать потоковый шифр». Поэтому я внедряю RC4, так как это относительно просто.
Я не использую ключ и отбрасываю первые 100000 бит, потому что начало RC4 немного смещено, тем более что я пропустил расписание ключей. Но я ожидаю, что он пройдет ваш тест даже без этого (экономя 20 символов кода).
Обычно можно вывести полный байт за цикл, но преобразование в двоичный код довольно уродливо в C #, поэтому я просто отбрасываю все, кроме младшего значащего бита.
Или без пробелов:
C #, 156 символов, работает в режиме оператора LinqPad. Для полной программы на C # добавьте обычный шаблон.
Мы также могли бы использовать встроенные крипто примитивы (решение Cheater):
(C #, 99 символов, работает в режиме операторов LinqPad. Для обычного компилятора C # вам нужно добавить немного шаблона)
Вывод криптографических хеш-функций разработан таким образом, чтобы он был неотличим от случайных данных, поэтому я ожидаю, что он пройдет все тесты на случайность (умирать сложнее, ...), которые вы кидаете, но мне лень это проверять.
источник
С, 52 символа
Это 10-битный LFSR, результаты теста:
источник
a
должен начинаться с 1 (при условии, что он вызывается без аргументов). Кроме того, вы можете вставитьa=
посередине, что-то вродеa=a/2^-!putchar(49-a%2)%576
(взять некоторые свободы с алгоритмом)a
, я изменил ее из-за "The program must not take any input from any external sources
"Sage / Python
Эта программа печатает самые правые двоичные цифры, которые являются общими для каждой достаточно высокой башни возведения в степень 3 3 3 3 . , , Для всего, что когда-либо могло быть сгенерировано, это самые правые двоичные цифры числа Грэма . Последовательность цифр бесконечна и не является периодической.
Для 1000 цифр это заняло менее 2 секунд; однако время будет увеличиваться намного быстрее, чем линейно по количеству цифр.
Результаты испытаний с использованием программы ОП :
(См. Являются ли самые правильные цифры G случайными? Более 32000 цифр и дополнительные статистические тесты.)
источник
Ява,
371317Основан на 128-битном LFSR (биты взяты из заметки приложения xilinx 52 )
РЕДАКТИРОВАТЬ: я не был удовлетворен использованием BigInteger, поэтому эта версия не. Сохранено несколько персонажей. Вывод может быть немного менее случайным, так как я не мог придумать хороший метод «посева».
Новый код: Аргументы: BITS_TO_PRINT
Старая версия: Аргументы: SEED, BITS_TO_PRINT
Новая версия: пример вывода, биты = 100:
источник
JavaScript - от 1 мс до 2 мс для 1000 псевдослучайных битов (от 139 мс до 153 мс для 100000 бит)
Это решение использует тот факт, что квадратные корни иррациональны и, следовательно, в значительной степени случайны. По сути, для запуска требуется квадратный корень из 2, преобразует его в двоичный, выбрасывает начальную часть, совпадающую с предыдущим корнем, добавляет ее к случайной строке, повторяет со следующим большим числом (или возвращается к 2, если число повторяется и имеет длину не менее 30 бит) и возвращает случайную строку, если она достаточно длинна.
Я еще не проходил тесты, но думаю, что это хорошо с ними справится. Вот скрипка, чтобы вы могли увидеть это в действии. Для моего времени я просто запускал программу несколько раз и принимал самые быстрые и самые медленные значения в качестве диапазонов.
источник
питон
Должен иметь период около 2 ^ 512.
источник
Perl, 44 байта
Я знаю, что это не гольф-код, но я всегда был поклонником младших бит простой квадратичной функции, например:
Период длиннее 3 миллиардов, но мне не хватило места на диске, чтобы рассчитать больше.
источник
$x=1/7;print substr($x*=4-4*$x,9,1)%2while 1