¿Qué mejor problema para PCG.SE que implementar PCG, un mejor generador de números aleatorios ? Este nuevo artículo pretende presentar un generador de números aleatorios estadísticamente óptimo, rápido, difícil de predecir, pequeño.
Su implementación mínima de C es de aproximadamente nueve líneas:
// *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));
}
(a partir de: http://www.pcg-random.org/download.html )
La pregunta es: ¿puedes hacerlo mejor?
Reglas
Escriba un programa o defina una función que implemente PCG en enteros sin signo de 32 bits. Esto es bastante amplio: puede imprimir una secuencia infinita, definir una pcg32_random_r
función y la estructura correspondiente, etc.
Debe poder sembrar su generador de números aleatorios de manera equivalente a la siguiente función 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);
}
(a partir de: pcg_basic.c:37
)
Llamar al generador de números aleatorios sin sembrarlo primero es un comportamiento indefinido.
Para verificar fácilmente su envío, verifique que, cuando se siembra con initstate = 42
y initseq = 52
, el resultado es 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
Tanteo
Puntuación estándar. Medido en bytes. Lo más bajo es lo mejor. En caso de empate, la presentación anterior gana. Se aplican lagunas estándar .
Solución de muestra
Compila bajo gcc -W -Wall
cleanly (versión 4.8.2).
Compare su presentación con esto para asegurarse de obtener la misma secuencia.
#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;
}
Secuencia:
2380307335
948027835
187788573
3952545547
2315139320
3279422313
2401519167
2248674523
3148099331
3383824018
2720691756
2668542805
2457340157
3945009091
1614694131
4292140870
Respuestas:
CJAM,
1091071049891 bytesEsto usa algunos caracteres fuera del rango ASCII, pero todos están dentro de ASCII extendido, así que cuento cada carácter como un byte (en lugar de contar como UTF-8).
Esto es básicamente un puerto exacto del código C.
La función semilla es un bloque almacenado en
S
, y la función aleatoria es un bloque almacenado enR
.S
esperainitstate
yinitseq
en la pila y sembrar el PRNG.R
no espera nada en la pila y deja el siguiente número aleatorio en él.Dado que llamar
R
antes de llamarS
es un comportamiento indefinido, en realidad estoy definiendoR
dentroS
, así que hasta que use el bloque semilla,R
es solo una cadena vacía e inútil.El
state
se almacena en variableA
y elinc
se almacena enB
.Explicación:
Y aquí está el equivalente del arnés de prueba en el OP:
que imprime exactamente los mismos números.
Pruébalo aquí. Stack Exchange elimina los dos caracteres no imprimibles, por lo que no funcionará si copia el fragmento anterior. Copie el código del contador de caracteres en su lugar.
fuente
C, 195
Supuse que alguien debería publicar una implementación C más compacta, incluso si no hay posibilidad de ganar. La tercera línea contiene dos funciones:
r()
(equivalente apcg32_random_r()
) ys()
(equivalente apcg32_srandom_r()
). La última línea es lamain()
función, que se excluye del recuento de caracteres.Aunque el compilador se quejará, esto debería funcionar correctamente en una máquina de 64 bits. En una máquina de 32 bits que tendrá que añadir otros 5 bytes al cambio
#define L long
a#define L long long
( al igual que en esta demo Ideone ).fuente
srandom
función sea parte de su envío y debe incluirse en el recuento de caracteres. (Después de todo, quizás podría pensar en alguna forma inteligente de optimizar esto). Según mi recuento, esto elevaría su puntaje actual a 197.Julia
218199191 bytesCambiar el nombre de los tipos de datos más algunos otros pequeños trucos me ayudaron a reducir la longitud en 19 bytes adicionales. Principalmente omitiendo dos asignaciones de tipo :: Int64 .
Explicación de los nombres (con los nombres correspondientes en la siguiente versión sin golf):
Inicialice la inicialización con el estado 42 y la secuencia 52. Debido al programa más pequeño, debe indicar el tipo de datos explícitamente durante la inicialización ahora (ahorró 14 bytes de código más o menos). Puede omitir la asignación de tipo explícito en sistemas de 64 bits:
Produzca el primer conjunto de números aleatorios:
Resultado:
Realmente me sorprendió que incluso mi versión de Julia, que no aparece en los campos de golf, es mucho más pequeña (543 bytes) que la solución de muestra en C (958 bytes).
Versión sin golf, 543 bytes
Inicializa la semilla (estado inicial = 42, secuencia inicial = 52) con:
Entonces puedes crear números aleatorios con:
Aquí está el resultado de un script de prueba:
Como soy un programador abismal, me llevó casi un día hacerlo funcionar. La última vez que intenté codificar algo en C (en realidad C ++) fue hace casi 18 años, pero una gran cantidad de google-fu finalmente me ayudó a crear una versión funcional de Julia. Tengo que decir que he aprendido mucho durante unos días en codegolf. Ahora puedo comenzar a trabajar en una versión de Piet. Eso va a ser mucho trabajo, pero realmente quiero un generador de números aleatorios (bueno) para Piet;)
fuente