Что может быть лучше для PCG.SE, чем реализовать PCG, лучший генератор случайных чисел ? Эта новая статья претендует на то, чтобы представить быстрый, трудно предсказуемый, небольшой, статистически оптимальный генератор случайных чисел.
Его минимальная реализация C составляет всего около девяти строк:
// *Really* minimal PCG32 code / (c) 2014 M.E. O'Neill / pcg-random.org
// Licensed under Apache License 2.0 (NO WARRANTY, etc. see website)
typedef struct { uint64_t state; uint64_t inc; } pcg32_random_t;
uint32_t pcg32_random_r(pcg32_random_t* rng)
{
uint64_t oldstate = rng->state;
// Advance internal state
rng->state = oldstate * 6364136223846793005ULL + (rng->inc|1);
// Calculate output function (XSH RR), uses old state for max ILP
uint32_t xorshifted = ((oldstate >> 18u) ^ oldstate) >> 27u;
uint32_t rot = oldstate >> 59u;
return (xorshifted >> rot) | (xorshifted << ((-rot) & 31));
}
(с сайта http://www.pcg-random.org/download.html )
Вопрос: вы можете сделать лучше?
правила
Напишите программу или определите функцию, которая реализует PCG для 32-разрядных целых чисел без знака. Это довольно широко: вы можете распечатать бесконечную последовательность, определить pcg32_random_r
функцию и соответствующую структуру и т. Д.
Вы должны быть в состоянии заполнить ваш генератор случайных чисел эквивалентно следующей функции C:
// pcg32_srandom(initstate, initseq)
// pcg32_srandom_r(rng, initstate, initseq):
// Seed the rng. Specified in two parts, state initializer and a
// sequence selection constant (a.k.a. stream id)
void pcg32_srandom_r(pcg32_random_t* rng, uint64_t initstate, uint64_t initseq)
{
rng->state = 0U;
rng->inc = (initseq << 1u) | 1u;
pcg32_random_r(rng);
rng->state += initstate;
pcg32_random_r(rng);
}
(с: pcg_basic.c:37
)
Вызов генератора случайных чисел без его заполнения - это неопределенное поведение.
Чтобы легко проверить ваше представление, убедитесь, что при посеве с помощью initstate = 42
и initseq = 52
, вывод 2380307335
:
$ tail -n 8 pcg.c
int main()
{
pcg32_random_t pcg;
pcg32_srandom_r(&pcg, 42u, 52u);
printf("%u\n", pcg32_random_r(&pcg));
return 0;
}
$ gcc pcg.c
$ ./a.out
2380307335
счет
Стандартный зачет. Измеряется в байтах. Самый низкий - лучший. В случае ничьей побеждает более раннее представление. Стандартные лазейкиПрименяются .
Пример решения
Компилируется под gcc -W -Wall
чисто (версия 4.8.2).
Сравните вашу заявку с этим, чтобы убедиться, что вы получаете ту же последовательность.
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
typedef struct { uint64_t state; uint64_t inc; } pcg32_random_t;
uint32_t pcg32_random_r(pcg32_random_t* rng)
{
uint64_t oldstate = rng->state;
// Advance internal state
rng->state = oldstate * 6364136223846793005ULL + (rng->inc|1);
// Calculate output function (XSH RR), uses old state for max ILP
uint32_t xorshifted = ((oldstate >> 18u) ^ oldstate) >> 27u;
uint32_t rot = oldstate >> 59u;
return (xorshifted >> rot) | (xorshifted << ((-rot) & 31));
}
void pcg32_srandom_r(pcg32_random_t* rng, uint64_t initstate, uint64_t initseq)
{
rng->state = 0U;
rng->inc = (initseq << 1u) | 1u;
pcg32_random_r(rng);
rng->state += initstate;
pcg32_random_r(rng);
}
int main()
{
size_t i;
pcg32_random_t pcg;
pcg32_srandom_r(&pcg, 42u, 52u);
for (i = 0; i < 16; i++)
{
printf("%u\n", pcg32_random_r(&pcg));
}
return 0;
}
Последовательность:
2380307335
948027835
187788573
3952545547
2315139320
3279422313
2401519167
2248674523
3148099331
3383824018
2720691756
2668542805
2457340157
3945009091
1614694131
4292140870
Ответы:
CJam,
1091071049891 байтПри этом используются некоторые символы вне диапазона ASCII, но все они находятся в расширенном ASCII, поэтому я считаю каждый символ байтом (а не UTF-8).
Это в основном точный порт кода C.
Функция seed - это блок, который хранится в
S
, а функция random - это блок, который хранится вR
.S
ожидаетinitstate
иinitseq
в стеке и семян PRNG.R
ничего не ожидает в стеке и оставляет на нем следующее случайное число.Поскольку вызова
R
перед вызовомS
является неопределенным поведением, я на самом деле определяющимR
вS
, так пока вы не используете блок семян,R
это просто пустая строка и бесполезно.state
Хранится в переменнойA
иinc
сохраняется вB
.Объяснение:
А вот эквивалент испытательного жгута в ОП:
который печатает одинаковые цифры.
Проверьте это здесь. Stack Exchange удаляет два непечатаемых символа, поэтому он не будет работать, если вы скопируете приведенный выше фрагмент. Вместо этого скопируйте код из счетчика символов .
источник
С, 195
Я подумал, что кто-то должен опубликовать более компактную реализацию C, даже если у нее нет шансов на победу. Третья строка содержит две функции:
r()
(эквивалентноpcg32_random_r()
) иs()
(эквивалентноpcg32_srandom_r()
). Последняя строка - этоmain()
функция, которая исключается из числа символов.Хотя компилятор будет жаловаться, это должно работать правильно на 64-битной машине. На 32-битной машине вам придется добавить еще 5 байт изменения
#define L long
в#define L long long
( как в этом ideone демо ).источник
srandom
функция является частью вашего представления и должна быть включена в число символов. (В конце концов, возможно, вы могли бы придумать какой-нибудь умный способ оптимизировать это.) По моим подсчетам, ваш текущий счет увеличится до 197.Юлия,
218199191 байтПереименование типов данных и несколько других хитростей помогли мне сократить длину еще на 19 байтов. Главным образом, опуская два :: Int64 типа присваивания.
Пояснения к именам (с соответствующими именами в негольфированной версии ниже):
Инициализируйте seed с состоянием 42 и последовательностью 52. Из-за меньшей программы вам необходимо точно указывать тип данных во время инициализации (сохранено 14 байтов кода или около того). Вы можете опустить явное назначение типов в 64-битных системах:
Произведите первый набор случайных чисел:
Результат:
Я был действительно удивлен, что даже моя версия Джулии без заглядывания ниже так намного меньше (543 байта), чем пример решения в C (958 байтов).
Неуправляемая версия, 543 байта
Вы инициализируете начальное число (начальное состояние = 42, начальная последовательность = 52) с помощью:
Затем вы можете создать случайные числа с:
Вот результат тестового скрипта:
Поскольку я ужасный программист, мне потребовался почти день, чтобы заставить его работать. Последний раз, когда я пытался написать что-то на C (на самом деле C ++), было почти 18 лет назад, но многие google-fu наконец помогли мне создать рабочую версию Julia. Я должен сказать, что я многому научился всего за несколько дней на Codegolf. Теперь я могу начать работать над версией Piet. Это будет большая работа, но я действительно, очень хочу (хороший) генератор случайных чисел для Пита;)
источник