2016-04-02 21 views
6

Sono stato recentemente discusso l'inizializzazione di più generatori di numeri casuali dello stesso tipo nei commenti di un altro post e in quella discussione abbiamo chiesto le seguenti domande:Semina più generatori di numeri casuali

1) E 'una buona idea di creare più istanze dello stesso generatore di numeri casuali con semi diversi e utilizzare questi generatori di numeri casuali in diverse parti del programma?

2) In particolare, può la tecnica di creazione di generatori di numeri casuali usando la classe Random Net, seminati come sotto, e utilizzando ogni RNG in differenti contesti programma causare problemi:

int size = 64; // The number of RNGs to use 
int seed;  // Get seed using some normal technique 
Random[] r = new Random[size]; 

for (int i = 0; i < size; i++) 
{ 
    r[i] = new Random(seed + i); 
} 

3) Quale si consiglia invece se sono necessari più flussi di numeri casuali?

4) Come si consiglia di generare numeri casuali quando è richiesta la sicurezza del filo?

+0

Questa domanda è stata creata come risposta ai commenti in una risposta per la seguente altra domanda: [how-do-i-seed-a-classe-casuale-evitare-ottenere-duplicato-valori casuali] (http://stackoverflow.com/questions/1785744/how-do-i-seed-a-random-class-to-avoid-getting-duplicate-random-values/1785821) – Andrew

risposta

11

1) È una buona idea creare più istanze dello stesso generatore di numeri casuali con semi diversi e utilizzare questi generatori di numeri casuali in diverse parti del programma?

No. In generale, lo schema sopra non è raccomandato.

Nel suo libro The Art of Computer Programming, Volume 2: Algoritmi seminali. Addison-Wesley, Reading, MA, terza edizione, 1997, il Dr. Knuth afferma che

Non è facile inventare una fonte infallibile di numeri casuali.

In questo caso, segnalo che prendere sottosequenze da una sequenza casuale può essere meno casuale rispetto alla sequenza originale di numeri casuali:

Avviso l'implementazione di Random di Micosoft è basata su un generatore di subractive lagged-fibonacci:

Questo tipo di generatore di numeri casuali è noto per una correlazione a tre punti incorporato, dopo tutto, stiamo generando il prossimo numero casuale: Subtractive Lagged-Fibonacci Generator

Questi tipi di Random Number I generatori dipendono anche fortemente dall'inizializzazione del loro stato iniziale di 55 numeri. Una scarsa inizializzazione può portare a numeri casuali scarsi. Nel caso precedente, stati simili, possono risultare in numeri casuali correlati da ciascuno dei diversi generatori di numeri casuali. Microsoft consiglia anche contro questo nel loro posto di MSDN su System.Random: MSDN The System.Random class and thread safety:

Invece di istanziare i singoli oggetti casuali, si consiglia di creare una singola istanza a caso per generare tutti i numeri casuali necessari per la vostra applicazione.

Vedremo un esempio in cui un'inizializzazione particolare crea una forte correlazione tra i diversi generatori di numeri casuali e cerca alternative.

2) Ho implementato un programma che tenta di inizializzare 64 istanze di Random come descritto sopra in modo da osservare eventuali difetti visibili. Ho scelto un particolare inizializzazione come prova di concetto:

int size = 64; // The number of random numbers generators 
int length = 20; // The number of random numbers from each generator 
int steps = 18; // Move 18 steps forward in the beginning to show a particular phenomenon 

Random[] r = new Random[size]; 

for (int i = 0; i < size; i++) 
{ 
    r[i] = new Random(i + 1); 

    // move RNG forward 18 steps 
    for (int j = 0; j < steps; j++) 
    { 
      r[i].Next(3); 
    } 
} 


for (int i = 0; i < size; i++) 
{ 
    for (int j = 0; j < length; j++) 
    { 
      Console.Write(r[i].Next(3) + ", "); // Generate a random number, 0 represents a small number, 1 a medium number and 2 a large number 
    } 

    Console.WriteLine(); 
} 

Questo programma genera l'output mostrato qui, ogni riga rappresenta l'uscita da un altro RNG:

Output of the program

noti che le colonne evidenziati: in particolari luoghi gli RNG sembrano sincronizzarsi e produrre un output che non sembra indipendente l'uno dall'altro.

Vorrei anche aggiungere un'altra nota, che la creazione di un singolo elenco di numeri casuali e l'assunzione di un numero casuale dall'elenco di ogni riga produce anche numeri casuali dall'aspetto povero (l'RNG utilizzato qui è noto per aver fallito qualche statistica Dopotutto!).

3) Il tipo di RNG utilizzato dipende dal contesto. Alcuni potrebbero essere felici con l'output di cui sopra. In altri casi, l'RNG utilizzato potrebbe essere inutilizzabile (Monte Carlo Simulation e Cryptography sono due scenari in cui System.Random deve essere mai, anche per un flusso di numeri casuali).

Se è necessario estrarre più sottosequenze di numeri casuali, trovare un RNG che è stato progettato per questo scopo:

4) Infine, che cosa se voglio utilizzare System . Casuale in più thread? Microsoft MSDN ha la risposta nello stesso link di cui ho parlato sopra:

+0

Questo è molto più convincente di qualsiasi commenti ... anche se con solo 3 numeri tra cui scegliere in qualsiasi momento, non è * abbastanza * così sorprendente. (Se avessi mostrato lo stesso pattern con 'Next (100)', ad esempio, sarebbe ancora più sorprendente: –

+0

@JonSkeet è abbastanza sorprendente L'idea è di mostrare numeri alti, medi e bassi. "allo stesso tempo" emettono grandi numeri: c'è un'altra colonna visibile che ho perso, dopo la seconda 2. La probabilità che 13 numeri siano "piccoli" allo stesso tempo (mostrati sopra nella 2a colonna) è di circa 1 su 1,5 milioni Spesso usi numeri casuali simili per scegliere tra poche azioni o simulare un lancio di dadi.(Inoltre, non avrei mai potuto aggiungere tanti riferimenti e informazioni in un commento - sono in effetti, commenti.) – Andrew

+0

Ho aggiunto un link a questo post dalla mia risposta. Questo sembra un problema nell'usare semi consecutivi come qualsiasi altra cosa. Come ho postato nella mia risposta, un'altra alternativa sarebbe usare un "master" 'Random', bloccato una volta per thread per generare il seed per' Random' di quel thread. Provare questo approccio con il tuo codice di test non mostra lo stesso modello per me. Saresti d'accordo che è un miglioramento, o sei ancora fondamentalmente contrario all'approccio? –

1

Non so cosa sia "più flussi di numeri casuali" si intende. In numeri casuali non esiste alcuna relazione tra due numeri casuali, non c'è un ordine, ognuno è un'istanza autonoma.

Se si utilizza un PRNG crittografico, non è necessario alcun seeding. Si consideri il .net RNGCryptoServiceProvider Class.

+0

I PRNG crittografici sono in genere continuamente seminati con dati essenzialmente casuali quali temporizzazioni di interrupt della CPU e altre occorrenze in tempo reale che in alcuni casi includono le variazioni della velocità del piatto del disco rigido a causa della turbolenza dell'aria. Il numero successivo non è interamente deterministico per nessun test e l'output non è discernibile dalla casualità vera. Questi non sono semplici generatori di congruenza lineare. Non esiste un semplice maniero migliore per generare più casualità nel codice utente. – zaph