Si bien hay muchas preguntas de código de golf aquí que involucran aleatoriedad, aún no he visto una que realmente solicite la construcción de un generador algorítmico de números pseudoaleatorios. Hay una que le pide que genere una secuencia de bits, pero las pruebas de aleatoriedad proporcionadas en esa no fueron muy rigurosas, y no es código de golf.
El programa que escriba tendrá una única función invocable que devolverá un entero aleatorio de 0 a 4294967295. Esta función no debe invocar ninguna biblioteca u otras funciones que no se hayan escrito también como parte del programa, especialmente las llamadas a / dev / random o la biblioteca rand () incorporada en un idioma. Más específicamente, está limitado a los operadores básicos del lenguaje en el que está trabajando, como la aritmética, el acceso a la matriz y las declaraciones de control de flujo condicional.
La puntuación de su programa se calcula de la siguiente manera:
Score = C / R
Donde C es la longitud del código en caracteres, y R es el número de pruebas Diehard que su generador pasa (si su generador de números aleatorios no pasa al menos una prueba Diehard, su puntaje es infinito y está descalificado). Su generador pasa una prueba Diehard si el archivo que genera proporciona un rango de valores P que parecen estar distribuidos uniformemente a lo largo del intervalo [0, 1).
Para calcular R, use su generador de números aleatorios con su semilla predeterminada para generar un archivo de datos binarios de 16 MB. Cada llamada de la función devuelve cuatro bytes; Si su función es demasiado lenta para devolver bytes, esto supondrá una compensación para lograr un puntaje bajo por lo difícil que es probar. Luego, ejecútelo a través de las pruebas Diehard y verifique los valores P proporcionados. (No intente implementarlos usted mismo; use los que se proporcionan aquí )
La puntuación más baja gana, por supuesto.
fuente
Respuestas:
Mathematica, 32/15 = 2.133
Una implementación sencilla de BBS .
Archivo binario generado con:
Resumen de Resultados:
Lleno
random.bin
aquíArchivo de registro completo aquí.
fuente
28!-67
Es algo prohibitivo. ¿Hay un valor más pequeño que cabría en un entero de 64 bits?Perl 28/13 ≈ 2.15
archivo de registro aquí
Perl 29/13 ≈ 2.23
archivo de registro aquí
Estos son una especie de variación en un Xorshift , utilizando la división de punto flotante en lugar de un desplazamiento a la derecha. Ambos pasan 13 de 15 pruebas, fallando solo las pruebas 6 y 7.
No estoy exactamente seguro de cuánto dura el ciclo, pero debido a que el siguiente código no termina en un período corto de tiempo, es probable que sea el 2 32 completo :
Perl 39/10 = 3.9
Nota: si está buscando un PRNG Blum-Blum-Shub-esque, la solución de Keith Randall es mucho mejor que cualquiera de estos.
Al igual que con mi solución original a continuación, esta también es una implementación de Blum Blum Shub, con una gran diferencia. Utilizo un módulo ligeramente mayor que 2 32 ( M = 50971 • 84263 ), y cada vez que se encuentra un valor que no es un entero de 32 bits válido (es decir, mayor que 2 32 ), devuelve el siguiente valor en el rotación en su lugar. En esencia, estos valores se eliminan, dejando el resto de la rotación sin perturbaciones, lo que resulta en una distribución casi uniforme.
Parece haber ayudado. Además de pasar las mismas 9 pruebas que antes, ahora también pasa convincentemente la prueba de Distancia mínima. Puede encontrar un archivo de registro de muestra aquí .
Perl 33/9 ≈ 3.67 (¿No válido?)
Nota: esta solución puede considerarse inválida, ya que nunca se observará el 0,00037% superior del rango.
Una implementación rápida y sucia del Blum Blum Shub . Reclamo los siguientes resultados:
Puede encontrar un archivo de registro de muestra aquí , no dude en disputar cualquiera de los resultados. El archivo para diehard se puede generar de la siguiente manera:
y luego canalizando la salida en un archivo. Parece que la distancia mínima puede haber pasado, pero si la ejecuta varias veces, siempre está muy cerca de 1.0 , lo que indica un error.
Detalles
En general, el Blum Blum Shub es un PRNG terrible, pero su rendimiento se puede mejorar eligiendo un buen módulo. La M que he elegido es 7027 • 611207 . Ambos factores primos, p y q , tienen un residuo modular 3 (mod 4) y mcd (φ (p-1), φ (q-1)) = 2 , que es lo más bajo posible.
Aunque estos son los únicos criterios enumerados en la página wiki, no parece ser suficiente. Casi todo el módulo que probé falló en cada prueba. Pero hay un puñado que pasará algunas de las pruebas, y la que he elegido parece ser excepcionalmente buena, por cualquier razón.
Como nota final, la Prueba 5 por sí sola parece ser un indicador bastante bueno de lo bueno que es el PRNG. Si casi no pasa la Prueba 5, fallará al resto espectacularmente.
BONIFICACIÓN: Perl 62/14 ≈ 4.43
Solo por geekery, esta es una versión de 32 bits del PRNG utilizada en el Tetris original para NES. Sorprendentemente, ¡pasa 14 de las 15 pruebas!
Ejemplo de archivo de registro puede antes aquí .
Es cierto que el
1..37
bit no es una transcripción exacta. En la versión original, la rutina de entropía se actualiza 60 veces por segundo y luego se consulta a intervalos aleatorios, dependiendo en gran medida de la entrada del usuario. Para cualquiera que se preocupe por desmontar la ROM, la rutina de entropía comienza en0xAB47
.Seudocódigo de estilo Python:
fuente
Python, 46/15 = 3.0666
Utiliza exponenciación modular para generar aleatoriedad. 2 ** 32-5 es el primo más grande menor que 2 ^ 32. (El mismo trato con no poder ejecutar la prueba # 2).
fuente
\r
y\n
para\r\n
, lo que obviamente sesga los resultados. Una solución es escribir el archivo directamente usandof = open('file.bin', 'wb')
yf.write
.Rubí, 32/15 = 2.1333
Esta es la solución de Keith Randall, implementada en Ruby.
fuente
C # 144/15 = 9.6
Esto pasó todas las pruebas.
Con no demasiados caracteres más, pasa TestU01.
Resultado: http://codepad.org/iny6usjV
fuente
C # - 103/14 = 7.36
Resultados
Pasa todos excepto la prueba # 6
Vea los resultados en http://codepad.org/k1NSoyQW
Explicación
C # simplemente no puede competir con Ruby y Python por la brevedad, como de costumbre, pero disfruté intentarlo. Ciertamente, hay otros valores que funcionarán igual de bien (es decir, el valor inicial para j = 999 y el divisor = 277). Elegí estos después de una breve experimentación.
Con contenedor de creación de archivos
fuente
Python, 41/15 = 2.73333
Un poco de trampa usando la función hash incorporada, pero está integrada, por lo que no hay más trampa que usar otras incorporadas, como
len
. Por otro lado, me duele tener que pagar laglobal v;
declaración ...Pasa todas las pruebas de Diehard (tuve un problema con la prueba # 2, es SEGV en mi máquina OSX. Para mi puntaje, supongo que pasará).
Aquí hay un controlador para generar el archivo de 16 MB:
fuente
+
una función incorporada, y por lo tanto descalificada?+
y__add__
en python, o sobrecarga de operadores en c ++. Sé que estoy dividiendo los pelos, así que considera este ejemplo. En python, ¿puedo crear un mapa como este{'a':5}
:? Probablemente dirás que sí, pero luego considera que debajo de las sábanas, tehash('a')
llaman cuando haces eso.C, 38/15 = 2.533
No pude hacer que las pruebas Diehard funcionaran en mi máquina, pero pasa la suite PractRand por hasta 8 GB de salida, así que supongo que las pasaría a todas.
fuente
Brain-Flak , 344 / (pendiente)
Pruébalo en línea!
Esto funciona bien, pero los enlaces de las pruebas intransigentes están rotos :( así que hasta que obtengamos nuevos no tengo una puntuación final
Esto usa el Blum Blum Shub PRNG, por lo que debería pasar la mayoría de los casos. Los números utilizados son lo suficientemente grandes, no aparecerán patrones dentro de los 16 MB de casos de prueba
fuente
Objetivo-C, 40/1 = 40
Enfoque bastante inteligente, explotando
.hash
para hacer trampa aquí, pero me gustafuente