2010-10-30 18 views
14

Necesito una semilla para una instancia de la clase Random de C#, y he leído que la mayoría de las personas usa el contador de tics de la hora actual para esto. Pero ese es un valor de 64 bits y la semilla necesita ser un valor de 32 bits. Ahora pensé que el método GetHashCode(), que devuelve int, debería proporcionar un valor razonablemente distribuido para su objeto y esto puede usarse para evitar usar solo los 32 bits más bajos del conteo de ticks. Sin embargo, no pude encontrar nada sobre el GetHashCode() del tipo de datos Int64.Siembra de un generador de números pseudoaleatorios en C#

Por lo tanto, sé que no va a importar mucho, pero el siguiente funciona tan bien como creo (no puedo aleatoriedad de prueba y error), o tal vez funciona igual que el uso de (int)DateTime.Now.Ticks como semilla ? ¿O tal vez incluso funciona peor? ¿Quién puede arrojar algo de luz sobre esto?

int seed = unchecked(DateTime.Now.Ticks.GetHashCode()); 
Random r = new Random(seed); 

Editar: ¿Por qué necesito una semilla y no dejar que el constructor Random() hacer el trabajo? Necesito enviar la semilla a otros clientes que usan la misma semilla para la misma secuencia aleatoria.

+2

Olvidó escribir su * argumento realmente bueno * para necesitar una semilla. –

+1

Bueno, agregué ese _muy buen argumento_ ahora. :) – Virtlink

Respuesta

32

new Random() ya utiliza la hora actual. Es equivalente a new Random(Environment.TickCount).

Pero esto es un detalle de implementación y puede cambiar en futuras versiones de .NET

le recomiendo usar nueva aleatorio() y sólo proporcionan una semilla fijo si desea obtener una secuencia reproducible de valores aleatorios seudo .

Ya que necesita una semilla conocida simplemente use Environment.TickCount como lo hace MS. Y luego transmitirlo a las otras instancias del programa como semilla.

Si crea varias instancias de Random en un intervalo corto (podría ser de 16ms), se pueden sembrar con el mismo valor y así crear la misma secuencia pseudoaleatoria. Pero eso probablemente no sea un problema aquí. Esta falla común se debe a que Windows actualiza la hora actual (DateTime.Now/.UtcNow) y TickCount (Environment.TickCount) solo cada pocos milisegundos. El intervalo exacto depende de la versión de Windows y de qué otros programas se estén ejecutando. Los intervalos típicos en los que no cambian son 16 ms o 1 ms.

+2

+1 por mencionar que el único momento para proporcionar realmente su propio valor inicial es cuando desea reproducir una secuencia específica de valores. Piense en las líneas de la opción "número de juego" de Windows Solitaire. –

+0

He editado mi pregunta. Sé sobre el 'nuevo constructor de Random()', pero necesito la semilla. – Virtlink

+0

@AndrewBarber O si itera el método/bloque fuera de la generación de Aleatorio, necesita semillas únicas y desea evitar el riesgo de colisiones debido a una resolución de tiempo insuficiente, tal como escribe CodesInChaos. – Alex

29

Si necesita sembrarlo con algo más que la hora actual (en cuyo caso se puede utilizar el constructor por defecto), puede utilizar esto:

Random random = new Random(Guid.NewGuid().GetHashCode()); 
+3

¿Y por qué sería mejor que 'DateTime.Now.Ticks.GetHashCode()'? – Virtlink

+17

Es mejor porque no sufre el problema de que 'DateTime.Now' solo cambia cada pocos milisegundos. Con este método, es muy poco probable que dos instancias de azar obtengan la misma semilla incluso cuando se inicializan en sucesión rápida. – CodesInChaos

+1

¿Y está seguro de que no hay colisiones hash? –

0

que tenía una pregunta similar, a seleccione un conjunto aleatorio de preguntas de una lista más amplia de preguntas. Pero cuando uso el tiempo como semilla da el mismo número aleatorio.

Así que aquí está mi solución.

int TOTALQ = 7; 
    int NOOFQ = 5; 

    int[] selectedQuestion = new int[TOTALQ]; 

    int[] askQuestion = new int[NOOFQ]; 

    /* Genarae a random number 1 to TOTALQ 
    * - if that number in selectedQuestion array is not o 
    * -  Fill askQuestion array with that number 
    * -  remove that number from selectedQuestion 
    * - if not re-do that - - while - array is not full.  
    */ 

    for (int i = 0; i < TOTALQ; i++) // fill the array 
     selectedQuestion[i] = 1; 

    int question = 0; 

    int seed = 1; 

    while (question < NOOFQ) 
    {  
     DateTime now1 = new DateTime(); 
     now1 = DateTime.Now;  
     Random rand = new Random(seed+now1.Millisecond); 
     int RandomQuestion = rand.Next(1, TOTALQ); 

     Response.Write("<br/> seed " + seed + " Random number " + RandomQuestion); 



     if (selectedQuestion[RandomQuestion] != 0)  
     { 
      selectedQuestion[RandomQuestion] = 0; // set that q =0 so not to select   
      askQuestion[question] = selectedQuestion[RandomQuestion]; 
      Response.Write(". Question no " + question + " will be question " + RandomQuestion + " from list "); 
      question++; 
     } 

     seed++;   

    } 
Cuestiones relacionadas