2010-02-14 40 views
11

Sto cercando di generare un numero casuale compreso tra 1 e 5 milioni. Il processo non deve essere veloce (anche se sarebbe bello se lo fosse), ma deve essere il più casuale possibile (non so nulla è casuale). Ho una varietà di fonti di dati per il seme.Numeri casuali con C#

Non sono sicuro se la classe .NETRandom sarà sufficiente per questo.

Questo sarà utilizzato per selezionare un biglietto vincente.

+5

Definire in modo chiaro e preciso "il più possibile casuale". Per ottenere un segnale che sia in realtà "il più casuale possibile" hai bisogno di una fonte di entropia - il seme - che abbia più bit di entropia rispetto all'elemento casuale generato da quel seme. Quindi, se hai già una varietà di fonti di dati per il seme, e sono ad alta entropia, allora hai già finito. Estrai solo 24 bit dalla tua fonte di entropia, e questo ti dà un numero tra 0 e 16 milioni che è ** il più casuale possibile data la tua fonte di entropia **. –

+2

Inoltre, sarebbe di grande aiuto se tu descrivessi per cosa userai questo numero casuale. –

+3

Re: il tuo aggiornamento: ora non sei più solo nel regno della matematica e della tecnologia, ma nel regno delle normative legali. La maggior parte delle persone che leggono questo non sono avvocati che hanno familiarità con le leggi riguardanti le caratteristiche che un dispositivo che sceglie il vincitore di una lotteria deve possedere. Consiglierei di consultare un avvocato e uno statistico prima di passare più tempo a perseguire una soluzione tecnica. Certamente nessuna * semplice * soluzione "pseudo casuale" sarà accettabile; si può facilmente capire quale sia il prossimo numero vincente da quelli precedenti con un PRNG. –

risposta

17

La classe System.Random probabilmente è abbastanza buono:

numeri

pseudo-casuali vengono scelti con uguale probabilità da un insieme finito di numeri. I numeri scelti non sono del tutto casuali perché un preciso algoritmo matematico viene utilizzato per selezionarli, ma sono sufficientemente casuali per scopi pratici. L'attuale implementazione della classe Random si basa sull'algoritmo del generatore di numeri casuali sottrattivi di Donald E. Knuth. Per ulteriori informazioni, vedi D. E. Knuth. "The Art of Computer Programming, volume 2: Algoritmi seminimetrici". Addison-Wesley, Reading, MA, seconda edizione, 1981.

L'unica cosa che dovete fare attenzione è che non riutilizzare lo stesso seme troppo spesso:

Se lo stesso seme viene usato ripetutamente, viene generata la stessa serie di numeri. Un modo per produrre sequenze diverse è quello di rendere il valore seme dipendente dal tempo, producendo quindi una serie diversa con ogni nuova istanza di Random.

+1

Vedere qui http://connect.microsoft.com/VisualStudio/feedback/details/634761/system -random-serious-bug È codificato in modo errato e quindi potrebbe non essere sufficiente – evolvedmicrobe

+0

@evolvedmicrobe: dopo aver eseguito una serie di test statistici su una versione di 'System.Random' con una patch che risolve quel particolare bug, non mi è chiaro che non ci sono altre cose sul RNG che dovrebbero essere più preoccupanti. Certo, ha diversi problemi: https://github.com/dotnet/corefx/issues/23298 – fuglede

7

Se è necessario il numero casuale crittografico, utilizzare la classe System.Security.Cryptography.RNGCryptoServiceProvider o utilizzare il metodo factory RandomNumberGenerator.Create() per creare il generatore di numeri casuali configurato in modo predefinito.

+3

RNGCryptServiceProvider funziona per riempire gli array di byte, quindi è necessario riconvertire in int e controllare che sia nell'intervallo corretto – zebrabox

+1

+1 per il commento di @ zebrabox, inoltre: se il valore generato è fuori intervallo, NON modificarlo (% operatore) poiché ciò potrebbe causare una distorsione per alcuni valori. Fai un giro e genera invece un altro valore. – devstuff

+0

@devstuff Quale è un motivo in più per non usare 'System.Random' dato che la loro implementazione di' Next (...) 'è distorta (non sembrano usare'% 'ma i numeri non sono ugualmente probabili). – CodesInChaos

0

caso di .NET dovrebbe andare bene per questo:

var random = new Random(System.DateTime.Now.Millisecond); 

int randomNumber = random.Next(1, 5000000); 
+1

Questo funziona solo per una variabile locale, è un incidente che aspetta di accadere. –

+0

Dovrebbe essere int randomNumber = random.Next (1, 5000001); come il metodo .Net restituisce un numero compreso del limite inferiore ma esclusivo del limite superiore. –

+0

Dipende dal contesto in cui viene utilizzato il numero se un millisecondo è un seme sufficientemente buono. Le slot machine sono state violate in questo modo. – Paco

5

vedi blog post di Jon Skeet Revisiting Randomness una buona recensione di come utilizzare Casualità:

Rivisitare casualità
Quasi ogni domanda Stack Overflow che include le parole "random" e "ripetuto "ha la stessa risposta di base. E 'uno dei "trucchi" più comuni in .NET, Java, e senza dubbio altre piattaforme: la creazione di un nuovo generatore di numeri casuali senza specificare un seme dipenderà dalla corrente istante di tempo. L'ora corrente come misurato dal computer non cambiamento molto spesso rispetto a quanto spesso è possibile creare e utilizzare un generatore casuale numero - così codice che crea più volte una nuova istanza di a caso e lo utilizza una volta finirà su mostrando molta ripetizione.

more...

+0

"altro ..." il link è ora rotto. –

1

Se siete alla ricerca di veri numeri casuali, allora si dovrebbe considerare l'utilizzo di un generatore di numeri casuali in linea che utilizza fenomeno naturale, come ad esempio http://www.random.org, che utilizza il rumore atmosferico. I veri numeri casuali fanno anche buoni semi per i generatori di numeri psuedo-casuali.

Sipwiz mostra come utilizzarlo in C# nella sua risposta: Generate random values in C#. È anche discusso qui: http://www.vcskicks.com/random-number-generator.php.

C'è un sacco di angoli per generatori di numeri casuali. Un'implementazione alternativa interessante è ISSAC (ttp: //burtleburtle.net/bob/rand/isaac.html), che contiene anche una buona discussione di bias e simili, e c'è anche una versione C# (http://burtleburtle.net/bob/rand/isaacafa.html).

5

In realtà c'era un articolo davvero buono che ho letto abbastanza di recente su diversi tipi di PRNG e su come funzionano in termini di diversi test di casualità. Sfortunatamente, non riesco a trovarlo ora. L'essenza di ciò, tuttavia, era che i generatori di numeri casuali predefiniti in quasi tutti i linguaggi di programmazione popolari sono piuttosto ingenui e hanno pregiudizi piuttosto significativi.

Un'altra risposta indica già che nessun PRNG, a prescindere da quanto sofisticato sia l'algoritmo, è sufficiente per le applicazioni crittografiche. Questo è vero. Dal momento che dici che questo sarà usato per "selezionare un biglietto vincente", ignoriamolo per ora.

L'algoritmo di Knuth utilizzato dalla classe .NET System.Random è ottimizzato principalmente per la velocità, non per la distribuzione casuale. È "abbastanza casuale" per molti scopi, che la maggior parte delle applicazioni non si allontanano mai troppo, ma nei campi di (a) gioco e (b) simulazione statistica, la maggior parte delle persone sembra pensare che sia una scelta sbagliata. È meglio degli LCG che erano il default nelle vecchie librerie, ma non si vuole ancora usarlo per qualcosa come un lotto.

Non fatevi ingannare dal pensare di utilizzare solo una fonte crittografica. Il problema con gli RNG crittografici è che riempiono un flusso di byte, ma trasformarli in un singolo numero casuale compreso tra x e y richiede che si esegua qualche aritmetica modulare (o arrotondamento, stesso risultato in entrambi i casi). E se la tua gamma casuale non si divide perfettamente in qualsiasi potenza di 2 è definita dalla lunghezza del byte, allora finirai con un pregiudizio nei numeri più bassi. I dati generati hanno un'alta entropia, ma il tuo risultato sarà distorto.

Come un semplice esempio, diciamo che ottieni un numero casuale "perfetto" da 1 a 10 e ora desideri trasformarlo in un numero casuale compreso tra 1 e 7. Come si fa? Il semplice calcolo di result % 7 sarà fortemente distorto verso i numeri 1-3. Ci sono alcuni modi per ridurre il bias quando si utilizza un RNG crittografico, ma il punto che sto cercando di fare è che gli RNG crittografici siano progettati per applicazioni crittografiche e l'utilizzo di uno di quelli per una simulazione Monte Carlo non è solitamente l'idea migliore.

Per quanto ne so, il PRNG "buono" più popolare oggi, utilizzato comunemente nelle applicazioni di gioco, è lo Mersenne Twister. C'è un .NET implementation here. Questo algoritmo supera tutti gli Diehard Tests per la distribuzione casuale; mostra quasi nessuna distorsione ed è una buona scelta quando si usano numeri casuali per applicazioni probabilistiche e statistiche.

La biblioteca scientifica GNU ha anche un numero di RNG algorithms e, non sorprendentemente, il Mersenne Twister è in cima alla lista.Tuttavia, alcuni degli altri valgono la pena di curiosare; RANLUX segna anche un buon punteggio nel test durissimo IIRC.

Eric ha ragione con il suo commento, naturalmente; tutte queste informazioni sono inutili se non hai requisiti tecnici specifici su "quanto casuale" hai bisogno che i tuoi numeri casuali siano. Sto usando una definizione che potrebbe essere applicabile a un'applicazione di gioco/gioco a impatto relativamente basso (cioè non un sito di gioco registrato con milioni di visitatori al giorno - ci sono regole più severe sulla casualità per quelli).

+0

La libreria C# non è basata sul metodo di Knuth, bensì la codifica – evolvedmicrobe

+0

@evolvedmicrobe: [Questo è ciò che dice la loro documentazione] (http://msdn.microsoft.com/en-us/library/system.random (v = vs .110) aspx). Hai una citazione o qualche prova per dimostrare il contrario? – Aaronaught

+0

sì, l'hanno tentato qui e mi sono verificato decompilando: http://connect.microsoft.com/VisualStudio/feedback/details/634761/system-random-serious-bug – evolvedmicrobe

3

Per generare un numero casuale, creare un oggetto della classe Random e quindi utilizzare la funzione Next di questo oggetto per generare un numero casuale. Ha molti sovraccarichi come:

Next(int minimum, int maximum); 
Next(int Maximum); 

dove è possibile specificare l'intervallo minimo e massimo tra cui si desidera il numero casuale.

Codice frammento:

Random random = new Random(); 
int maxValue = 100; 

int r = random.Next(maxValue); 
3

classe L'System.Random è molto problematica e non è una buona misura con il requisito. In teoria, dovrebbe fornire risultati migliori di molti altri generatori pseudo casuali. Si tratta di una porta diretta e letterale di codice C di esempio per un generatore di Fibonacci ritardato (LFG) fornito a pagina 283 della seconda edizione di "Numerical Recipes in C" (il codice è stato riscritto in edizioni successive). I LFG utilizzano un algoritmo migliore rispetto ai generatori di lineari convenzionali (LCG) utilizzati in molte altre librerie (ad es. Java).

Sfortunatamente, l'implementazione di Microsoft della classe System.Random ha un bug in esso. Vedere http://connect.microsoft.com/VisualStudio/feedback/details/634761/system-random-serious-bug per ulteriori informazioni. Sembra che qualcuno abbia digitato accidentalmente "21" quando intendeva digitare "31". Questo compromette le caratteristiche pseudo-casuali dell'algoritmo. Il link include una spiegazione da parte della SM sul motivo per cui si sentono in grado di correggere l'errore in questa fase.

+0

Grazie per la risposta dettagliata. Abbiamo finito per utilizzare un hardware rng ma grazie per le informazioni e il link! – LiamB