2011-11-29 15 views
11

Duplicar posible:
Why does it appear that my random number generator isn't random in C#?
How can I generate truly (not pseudo) random numbers with C#?Creación de un verdadero azar

He creado un juego de dados en el que los dados se basa en un percentil, 1-100.

public static void Roll() 
{ 
    Random rand = new Random((int)DateTime.Now.Ticks); 
    return rand.Next(1, 100); 
} 

Pero no me siento como si fuera un verdadero azar según la hora actual.

Si hago

for (int i = 0; i < 5; i++) 
{ 
    Console.WriteLine("#" + i + " " + Roll()); 
} 

todos ellos serían los mismos valores, debido a que el DateTime.Now.Ticks no cambió, se sembró el mismo número.

Estaba pensando que podría generar una nueva semilla aleatoria si la semilla era la misma debido al tiempo actual, pero no se siente como un honesto "re-roll"

¿Qué debo hacer para intentar y replicar una tirada de dados casi real/honesta? ¿Debería usar la clase RNGCryptoServiceProvider para generar rollos?

+0

Sugiero leer esto: http://csharpindepth.com/Articles/Chapter12/Random.aspx – Oded

+1

hay muchas variaciones de esta pregunta en SO. Aquí está uno de ellos ... [¿Por qué parece que mi generador de números aleatorios no es aleatorio en C#?] (Http://stackoverflow.com/questions/932520/why-does-it-appear-that-my- random-number-generator-isnt-random-in-c) ... Marcado como engañado. (Solo debe tener una única instancia estática de su Aleatorio en lugar de un nuevo Aleatorio para cada Tirada) – spender

+0

¿qué es "verdadero aleatorio"? – Sandy

Respuesta

10

DateTime.Now.Ticks solamente tiene una resolución de approximately 16ms, por lo que si se crea un Random con que la sobrecarga varias veces dentro de una "ranura" 16ms todos ellos serán sembradas con el mismo valor y por lo tanto obtendrá la misma secuencia.

inicializar su Random fuera de su bucle de modo que se produce una sola secuencia Random, en lugar de crear cada vez dentro del bucle, que podría resultar en Randoms ser cabeza de serie con el mismo valor y así producir la misma secuencia.

actualización

Mi punto anterior de que el constructor predeterminado inicializa Random con las señales de la CPU era incorrecta, el constructor por defecto utiliza realmente Environment.TickCount que es:

un entero de 32 bits que contiene la cantidad de tiempo en milisegundos transcurridos desde la última vez que se inició la computadora.

Que aún tiene una resolución baja. Si realiza varias instancias de Random en sucesión rápida, pueden crearse fácilmente dentro del mismo intervalo de tiempo y, por lo tanto, tienen el mismo valor inicial y crean la misma secuencia. Crea una instancia única de Random y úsalo.

actualización

En relación con sus comentarios, si desea generar una secuencia aleatoria a través de múltiples hilos, consulte el siguiente artículo de Jon Skeet que discute un contenedor seguro para subprocesos:

https://codeblog.jonskeet.uk/2009/11/04/revisiting-randomness

+0

La inicialización aleatoria() predeterminada es la marca actual de la CPU? – Kyle

+0

@Kyle He actualizado mi respuesta. –

+0

Gracias. ^.^No sé si todavía debo usar random porque uso threads. He leído al azar no es seguro para subprocesos. Si inicializo random() fuera de la función, creo que causará problemas. – Kyle

4

Debe crear su clase Aleatoria solo una vez fuera de su función de Roll y sembrarla con un valor único.

Está recreando su Aleatorio cada vez que llama a Roll que causa los 'números no aleatorios'.

+0

Gracias por identificar esto. ^^ – Kyle

0

Supongo que está llamando al método Roll() tan rápido que Now.Ticks es el mismo?

La forma más sencilla de evitar esto sería en lugar de crear una nueva instancia Random() cada vez que llame Roll() crear una variable estática para mantener una sola instancia de Random().

+0

Sí, ese era el problema. Gracias por la ayuda. – Kyle

1

¿Debo usar la clase RNGCryptoServiceProvider para generar rollos?

Si este es un juego serio con dinero en juego, entonces: Sí.

+1

El dinero no está en juego. Quería replicar rollos realistas. Entonces, cuando la gente juega, se siente como si realmente tiraran un dado. – Kyle

+0

Aleatorio será más que suficiente, pero lea la otra respuesta sobre la siembra. –

+0

Voy a usar esto porque random() no es seguro para subprocesos. Sin embargo, hoy aprendí algunas cosas más sobre random(). – Kyle

0

La forma habitual de usar generadores de números aleatorios es sembrarlos una vez, guardarlos y llamarlos repetidamente a lo largo de su programa. Siempre que se siembra desde un valor adecuado al comienzo, debe obtener una aleatoriedad aceptable, suponiendo que el generador que está utilizando utiliza una función que devuelve elementos que son convenientemente aleatorios para sus propósitos. Por lo tanto, guarde su instancia Random fuera de la función Roll(), siembre la primera vez que la use y luego llame a Next() cada vez que necesite otro número.

Cuando llega al grano, no existe la generación de números aleatorios en una computadora, solo secuencias seudoaleatorias basadas en una semilla. Sin embargo, los humanos son terribles para identificar la aleatoriedad, por lo que generalmente está bien.

+0

lol @ humans que identifica la aleatoriedad. Gracias por la ayuda. ^^ – Kyle

7

pseudo-aleatorios generadores de números como Random sólo deben ser sembradas vez, por lo que:

private static Random _rand = new Random(); 
public static int Roll() 
{ 
    return _rand.Next(1, 100); 
} 

(Tenga en cuenta que hice el valor de retorno int en lugar de void; la función Roll como se cita en los resultados de la pregunta en un error de sintaxis.)

Pero su título dice "Creando un verdadero azar". Random no hará eso para usted, es un generador de números pseudo-random, lo que significa que es determinista, apenas difícil de predecir si no conoce la semilla. Por lo general, eso es lo suficientemente bueno para la mayoría de los propósitos, pero si necesita aleatoriedad real, necesita una fuente de entropía. http://random.org es uno popular.

+1

Gracias por mencionar eso. Lo estaba reescribiendo en el hilo basado en la memoria, era un error de sintaxis. Gracias por la ayuda. – Kyle