2011-02-01 30 views
6

Estoy usando Random para generar una secuencia de números aleatorios. Estoy construyendo el objeto aleatorio una sola vez y luego dentro del ciclo generando los valores aleatorios (300 de ellos). El problema es que una vez que consigo todos los valores y hacer una especie de ellos me di cuenta de que algunos de ellos son iguales y/o secuencial: estoy generando números del 0 al 50000.Aleatorio no es aleatorio

Ésta es mi guión:

Random rnd = new Random(); 
for (int n=0; n < 300; n++) 
{ 
    int RndNumber = rnd.Next(0, 50000); 
    System.Threading.Thread.Sleep(3); 
} 

¿Alguien puede tener una idea de por qué sucede esto, y cómo puedo mejorar esto para que sea más aleatorio?

+0

Usted necesita ser específico acerca de cómo se defina "más al azar" – cordialgerm

+1

por qué estás ordenando números aleatorios? ¿eso no derrota el propósito de generar números aleatorios? – helloworld922

+0

¿Podría ser el problema con la clasificación? – Marlon

Respuesta

11

Como una explicación de por qué que se está viendo el duplicado de vez en cuando, Jason's answer es correcto.

Si lo que quiere es 300 números aleatorios distintos, ¿qué tal algo como esto?

static IEnumerable<int> GetRandoms(int min, int max) 
{ 
    var rand = new Random(); 
    while (true) 
    { 
     yield return rand.Next(min, max); 
    } 
} 

var distinctRandoms = GetRandoms(0, 50000).Distinct().Take(300); 
+0

Sí, da un número distinto pero todavía tiene números de conjunción, esto se debe a la paradoja del cumpleaños, creo. Esto parece estar cumpliendo con lo que necesito hacer. Gracias Dan Tao – Terrence

+2

Ten en cuenta que forzando la distinción, de hecho estás dañando la "aleatoriedad" - la distribución ya no es (pseudo) uniforme. – bavaza

+1

@bavaza: No estoy seguro de si ese comentario está dirigido a mí o al OP, pero creo que el OP en realidad no quiere verdadero * randomness *; de lo contrario, no haría esta pregunta. Por supuesto, tiene razón en que la eliminación de duplicados compromete la aleatoriedad de los datos, al igual que la clasificación. –

21

Así que esta es la paradoja del cumpleaños *. Cuando se dibuja 300 números del 50000 la probabilidad aproximada de que al menos dos de ellos son iguales es

p(300) = 1 - exp(-300 * 300/(2 * 50000)) 
     = 0.59 

(que podría trabajar a cabo la probabilidad exacta, pero soy vago !.)

Por lo tanto, es más probable que tengas una colisión. Secuencial es incluso más probable (ahora no necesita una colisión, solo necesita n - 1 y n o n y n + 1 para recibir el resultado de n).

El azar es voluble.

*: En caso de que no esté familiarizado con esto, dice que si tiene veintitrés personas en una habitación, es más probable que al menos dos personas compartan el mismo cumpleaños. .

!: Bien, lo resolví. Es ,5953830515549951746819986449 ....

+2

+1, muy buena explicación – Marlon

11

Investigación:

Hola chicos,

si se utiliza el constructor sin parámetros new Random() la semilla está en función de la servertime actual.

Aleatorio(): "Inicializa una nueva instancia de la clase aleatoria, utilizando una función del tiempo" http://msdn.microsoft.com/en-us/library/system.random.aspx

Por lo tanto, si trato de esta manera:

for(int i = 0; i < 1000; i++) 
{ 
    Random ran = new Random(); 
    Console.WriteLine(ran.Next(50001)); 
} 

¡Solo recibo 3 números diferentes alrededor de 300 veces en un millar de llamadas! No es tan al azar ...

Al establecer la semilla en el constructor new Random(0) se devuelve una serie de números corregidos.

p. Ej. new Random(0).Next(50)siempre! devuelve 36. Inténtalo tú mismo, si no confías en mí;

Lo que necesitamos para los números aleatorios "reales" es una semilla cambiante, eso es independiente del tiempo.

estoy usando Hashcode de valores cambiantes:

por ejemplo Guid.NewGuid().GetHashCode() o DateTime.Now.GetHashCode()


Resultado:

Random ran = new Random(Guid.NewGuid().GetHashCode()); 
for(int i = 0; i < 1000; i++) 
{  
    Console.WriteLine(ran.Next(50001)); 
} 

o (para un mejor rendimiento):

for(int i = 0; i < 1000; i++) 
{ 
    int val = Guid.NewGuid().GetHashCode() % 50001; 
    val = val > 0 ? val : -val; 
    Console.WriteLine(val); 
} 

PS: El máximo de la -method siguiente (max) es siempre máximo - 1;

-> ran.Next (11) puede devolver 0,1,2, ..., 8,9,10. ¡No 11!

Saluda Bahamut =)

+1

'DateTime.Now.GetHashCode()' no es mejor que la inicialización predeterminada. – CodesInChaos

+0

+1 Esto fue lo suficientemente "aleatorio" para mi gusto :) No hay grupos de números cuando intenté generar 2000 de ellos. – rtpHarry

+0

@CodesInChaos Su derecho.No sé exactamente si el constructor predeterminado de Random usa el código hash DateTimes o milisegundos o lo que sea, pero no es aleatorio en absoluto – Bahamut