2011-01-27 32 views
7

Duplicar posible:
Why does this Random Number Generator not random?¿Por qué no es aleatorio() aleatorio?

que tienen este programa de prueba:

static void Main(string[] args) 
{ 
    var randomNumbers = new Dictionary<int, int>(); 
    foreach (var s in Enumerable.Range(1, 500)) 
    { 
     var rand = Rand5(); 
     if (!randomNumbers.ContainsKey(rand)) 
      randomNumbers.Add(rand, 1); 
     else 
      randomNumbers[rand] += 1; 
    } 

    randomNumbers 
     .ToList() 
     .ForEach(x => Console.WriteLine("{0}: {1}", x.Key, x.Value)); 
    Console.ReadLine(); 
} 

static int Rand5() 
{ 
    System.Threading.Thread.Sleep(1); 
    return new Random().Next(1, 6); 
} 



Si comento hacia fuera System.Threading.Thread.Sleep(1);, consigo

5: 500 

Pero si elimino esa línea, obtengo números aleatorios.

2: 87 
4: 94 
1: 116 
5: 108 
3: 95 

¿Por qué es importante la línea de código? ¡Gracias!

+0

Supongo que es inútil marcar tales preguntas como engañados, ya que probablemente alrededor de un tercio de todas las * preguntas etiquetadas al azar son el mismo problema. – Joey

Respuesta

10

Como han dicho otros, new Random() semillas del generador de números aleatorios de la hora actual del sistema.

Tengo an article que describe esto con más detalle, incluidas las soluciones al problema, que pueden serle útiles. Básicamente, desea utilizar la misma instancia de Random varias veces, pero observando que es no thread-safe.

+0

Gracias por la respuesta con una explicación detallada. Por cierto, estoy leyendo tu C# en Profundidad 2 :) – bla

+0

Guau, ese es un gran artículo. Entiendo el problema mejor que hace 10 minutos. –

+0

Es por eso que deseo que 'System.Random' fuera un singleton estático, inicializado de forma lenta. –

3

Porque se trata de utilizar el reloj como una semilla para la generación de números y cuando se genera números aleatorios de esa manera, se obtiene el mismo número

2

El generador de números aleatorios se basa parcialmente en el reloj del sistema, y ​​C# es demasiado maldito rápido batiéndolos ...

11

El tipo Random está sembrado por defecto de acuerdo con la hora actual del sistema, que tiene una granularidad finita.

Llamar new Random().Next(1, 6) muchas veces en rápida sucesión construirá así muchos objetos Random con el mismo valor de inicialización, produciendo el mismo resultado. La llamada Thread.Sleep(1) "resuelve" este problema simplemente espaciando las construcciones más separadas en el tiempo, aumentando la probabilidad de valores de inicialización distintos.

Usted necesidad de mantener una Random objeto específico de una llamada a la siguiente:

var randomNumbers = new Dictionary<int, int>(); 
var random = new Random(); // Re-use this, don't keep creating new ones. 
foreach (var s in Enumerable.Range(1, 500)) 
{ 
    var rand = random.Next(1, 6); 
    // ... 
1

Si no sembrar el azar, se obtiene el mismo número que Random es un pseudo-aleatorio generador de

Mediante el uso de Thread.Sleep (1) que permite que el temporizador para avanzar y generar un nuevo semilla autogenerada.

Una forma de "arreglar" es crear 1 objeto aleatorio y reutilizarlo (como algunos otros también respondieron), o utilizar un generador aleatorio diferente.

Más información sobre http://msdn.microsoft.com/en-us/library/ctssatww.aspx

0

Cualquier generador de números aleatorios que se utiliza es un número pseudo-aleatorio. Esto siempre tendrá un valor de inicialización predefinido y es bueno para las pruebas, pero no para la implementación de características de verdadera aleatoriedad.

Debe usar una secuencia numérica casi aleatoria para generar números aleatorios o mejor aún, la cadena Markovs para generar los mejores números aleatorios. Si planea usar una de esas funciones aleatorias, no tendrá nada que ver con la aleatoriedad real.