CJam, 16 14 13 bytes
0{Kmr(+esmr}g
Este tendrá una duración de un muy largo tiempo, ya que utiliza la marca de tiempo actual (del orden de 10 12 ) para determinar si el bucle debe terminar. Estoy usando esto como el envío, ya que es el más corto, pero hay dos alternativas de 14 bytes, que tienen sus propios méritos:
0{esmr(+esmr}g
Este no está limitado por el período del PRNG, ya que el rango de todos los números aleatorios depende de la marca de tiempo actual. Por lo tanto, esto debería ser capaz de producir cualquier número, aunque la probabilidad de números negativos, o incluso pequeños números positivos, es muy pequeña.
A continuación se muestra una versión equivalente que utiliza en 3e5
lugar de la marca de tiempo. Y 20
para el primer rango (como el envío de 13 bytes). Es mucho más rápido y también cumple con todas las reglas. Es una especie de caso limitante obtener una probabilidad del 50% para números más allá de 1,000,000 mientras se mantiene un tiempo de ejecución razonable y un tamaño de código pequeño. La explicación y la justificación matemática se refieren a esta versión:
0{Kmr(+3e5mr}g
Esto suele tardar unos segundos en ejecutarse. Puede reemplazarlo 5
con a 2
para que funcione aún más rápido. Pero luego, el requisito de la probabilidad del 50% solo se cumplirá para 1,000 en lugar de 1,000,000.
Estoy empezando en 0. Luego tengo un bucle, que rompo con probabilidad 1 / (3 * 10 5 ). Dentro de ese ciclo agrego un número entero aleatorio entre -1 y 18 (inclusive) a mi total acumulado. Hay una probabilidad finita (aunque pequeña) de que cada número entero se genere, con números enteros positivos que son mucho más probables que los negativos (no creo que vea uno negativo en su vida). Romper con una probabilidad tan pequeña e incrementar la mayor parte del tiempo (y agregar mucho más que restar) asegura que usualmente iremos más allá de 1,000,000.
0 "Push a 0.";
{ }g "Do while...";
Kmr "Get a random integer in 0..19.";
( "Decrement to give -1..18.";
+ "Add.";
3e5mr "Get a random integer in 0..299,999. Aborts if this is 0.";
Alguna justificación matemática:
- En cada paso agregamos 8.5 en promedio.
- Para llegar a 1,000,000 necesitamos 117,647 de estos pasos.
La probabilidad de que hagamos menos que este número de pasos es
sum(n=0..117,646) (299,999/300,000)^n * 1/300,000
que evalúa a 0.324402
. Por lo tanto, en aproximadamente dos tercios de los casos, daremos más 117,647 pasos, y fácilmente cada 1,000,000.
- (Tenga en cuenta que esta no es la probabilidad exacta, porque habrá alguna fluctuación sobre esos 8.5 promedio, pero para llegar al 50%, tenemos que ir más allá de 117,646 a unos 210,000 pasos).
- En caso de duda, podemos volar fácilmente el denominador de la probabilidad de terminación, hasta
9e9
sin agregar ningún byte (pero años de tiempo de ejecución).
... o 11 bytes?
Finalmente, hay una versión de 11 bytes, que tampoco está limitada por el período del PRNG, pero que se quedará sin memoria casi siempre. Solo genera un número aleatorio (basado en la marca de tiempo) en cada iteración, y lo usa tanto para incrementar como para terminar. Los resultados de cada iteración permanecen en la pila y solo se resumen al final. Gracias a Dennis por esta idea:
{esmr(}h]:+