2011-01-27 17 views
7

Eventuali duplicati:
Why does this Random Number Generator not random?Perché non è casuale() casuale?

ho questo programma di test:

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); 
} 



Se io commento System.Threading.Thread.Sleep(1);, ottengo

012.351.641,061 mila
5: 500 

Ma se disapprovo quella riga, ottengo numeri casuali.

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

Perché la riga di codice è importante? Grazie!

+0

Immagino che sia inutile marcare domande come i doppi perché probabilmente circa un terzo di tutte le domande * casuali * sono lo stesso problema .. – Joey

risposta

10

Come altri hanno detto, new Random() semi il generatore di numeri casuali dal momento sistema attuale.

Ho an article descrivendo questo in modo più dettagliato, comprese le soluzioni al problema, che potrebbero essere utili. Fondamentalmente si desidera utilizzare la stessa istanza di Random più volte, ma osservando che è non thread-safe.

+0

Grazie per la risposta con spiegazione dettagliata. A proposito, sto leggendo il tuo C# in Profondità 2 :) – bla

+0

Wow, questo è un grande articolo. Capisco il problema meglio di quanto ho fatto 10 minuti fa. –

+0

Questo è il motivo per cui vorrei che 'System.Random' fosse un singleton statico, inizializzato pigramente. –

3

Causa che sta utilizzando l'orologio come un seme per la generazione di numeri e quando si genera numeri casuali in questo modo, si ottiene gli stessi numeri

2

Il generatore di numeri casuali è basato in parte sul clock di sistema, e C# è troppo dannatamente veloce sfornandoli ...

11

Il tipo Random è seminato per impostazione predefinita in base al tempo di sistema corrente, che ha una granularità finita.

Chiamando il numero new Random().Next(1, 6) molte volte in rapida successione, verranno quindi costruiti molti oggetti Random con lo stesso valore di inizializzazione, producendo lo stesso risultato. La chiamata Thread.Sleep(1) "risolve" questo problema semplicemente spaziate le costruzioni più distanti nel tempo, aumentando la probabilità di valori seme distinti.

è necessario mantenere una specifica Random oggetto da una chiamata all'altra:

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

Se non inizializzare il caso, si ottiene lo stesso numero a caso è uno pseudo-random-generatore

Utilizzando Thread.Sleep (1) si consente il timer per avanzare e per generare un nuovo autogenerated-seme.

Un modo per "risolvere" è creare 1 oggetto casuale e riutilizzarlo (come anche altri hanno risposto), oppure utilizzare un generatore casuale differente.

Maggiori informazioni http://msdn.microsoft.com/en-us/library/ctssatww.aspx

0

Qualsiasi generatore di numeri casuali si utilizza è un numero pseudo-casuale. Questo avrà sempre un valore di seme predefinito ed è buono per il test ma non per l'implementazione di caratteristiche di casualità reale.

È consigliabile utilizzare una sequenza numerica quasi casuale per generare numeri casuali o, meglio ancora, la catena Markovs per generare i numeri casuali migliori. Se prevedi di utilizzare una di queste funzioni Random, non troverai nulla di simile alla casualità vera.