2011-11-29 6 views
11

Eventuali duplicati:
Why does it appear that my random number generator isn't random in C#?
How can I generate truly (not pseudo) random numbers with C#?Creazione di un vero e proprio caso

ho creato un gioco di dadi in cui i dadi si basa su un percentile, 1-100.

public static void Roll() 
{ 
    Random rand = new Random((int)DateTime.Now.Ticks); 
    return rand.Next(1, 100); 
} 

Ma non mi sembra un vero casuale basato sul tempo corrente.

Se faccio

for (int i = 0; i < 5; i++) 
{ 
    Console.WriteLine("#" + i + " " + Roll()); 
} 

sarebbero tutti gli stessi valori, perché la DateTime.Now.Ticks non è cambiata, è seminato lo stesso numero.

Stavo pensando che potrebbe generare un nuovo seme casuale se il seme è stato lo stesso a causa del tempo corrente, ma non si sente come un onesto "ri-roll"

Cosa devo fare per cercare e replicare un tiro di dadi vicino al vero/onesto? Dovrei usare la classe RNGCryptoServiceProvider per generare rotoli, invece?

+0

Suggerisco di leggere questo: http://csharpindepth.com/Articles/Chapter12/Random.aspx – Oded

+1

ci sono molte varianti di questa domanda su SO. Ecco uno di questi ... [Perché sembra che il mio generatore di numeri casuali non sia casuale in C#?] (Http://stackoverflow.com/questions/932520/why-does-it-appear-that-my- random-number-generator-isnt-random-in-c) ... Contrassegna come duplicato. (Dovresti avere una sola istanza statica del tuo Random piuttosto che un nuovo Random per ogni Roll) – spender

+0

cos'è "true random"? – Sandy

risposta

10

DateTime.Now.Ticks ha solo una risoluzione di approximately 16ms, quindi se si crea una Random con quel sovraccarico più volte in un 16ms "slot" saranno tutti seminate con lo stesso valore, per cui si ottiene la stessa sequenza.

inizializzare il Random di fuori del ciclo in modo che una singola sequenza Random viene prodotto, invece di creare ogni volta all'interno del ciclo che potrebbe risultare in Randoms essendo seminato con lo stesso valore e quindi produrre la stessa sequenza.

Aggiornamento

Il mio punto precedente, che il costruttore di default inizializzato Random con le zecche CPU non era corretta, il costruttore di default utilizza effettivamente Environment.TickCount che è:

Un intero con segno a 32 bit contenente la quantità di tempo in millisecondi trascorsi dall'ultima volta che è stato avviato il computer.

Che ha ancora una bassa risoluzione. Se si effettua più istanze di Random in rapida successione, essi possono essere facilmente creati all'interno della stessa fascia oraria e quindi hanno lo stesso valore del seme, e creare la stessa sequenza. Crea una singola istanza di Random e usala.

Aggiornamento

seguito ai vostri commenti, se si desidera generare una sequenza casuale tra più thread, vedere il seguente articolo di Jon Skeet che discute un thread-safe involucro:

https://codeblog.jonskeet.uk/2009/11/04/revisiting-randomness

+0

Il seme random() predefinito è ticks corrente della CPU? – Kyle

+0

@Kyle Ho aggiornato la mia risposta. –

+0

Grazie. ^.^Non so se dovrei ancora usare random perché uso i thread. Ho letto a caso non è thread-safe. Se inizializzo random() al di fuori della funzione, penso che causerà problemi. – Kyle

4

si dovrebbe creare una classe Random solo una volta fuori della vostra funzione roll e seminare con un valore unico.

Stai ricreando il tuo Casuale ogni volta che chiami Roll che causa i 'numeri non casuali'.

+0

Grazie per l'identificazione di questo. ^^ – Kyle

0

Suppongo che chiami il metodo Roll() così rapidamente che lo è lo stesso?

Il modo più semplice per aggirare questo sarebbe piuttosto che per creare una nuova istanza Random() ogni volta che si chiama Roll() creare una variabile statica per contenere una singola istanza di Random().

+0

Sì, questo era il problema. Grazie per l'aiuto. – Kyle

1

Devo utilizzare la classe RNGCryptoServiceProvider per generare rotoli, invece?

Se questo è un gioco serio con soldi in ballo allora: Sì.

+1

Il denaro non è in gioco. Volevo replicare rotoli realistici. Quindi, quando le persone giocano, sembra che stiano davvero tirando un dado. – Kyle

+0

Il casuale sarà più che sufficiente, ma leggerà l'altra risposta sulla semina. –

+0

Lo userò perché random() non è thread-safe. Oggi ho imparato un po 'di cose su random(). – Kyle

0

Il modo usuale di utilizzare generatori di numeri casuali è di seminarli una volta, salvarli e richiamarli ripetutamente per tutto il programma. Finché si semina da un valore adeguato all'inizio, si dovrebbe ottenere una casualità accettabile - supponendo che il generatore che si sta usando sia utilizzando una funzione che restituisce cose che sono opportunamente casuali per i propri scopi. Quindi, salva la tua istanza Casuale fuori dalla funzione Roll(), inizializza la prima volta che viene utilizzata, quindi chiama Avanti() su di essa ogni volta che ti serve un altro numero.

Quando ci arrivi, non esiste una vera generazione di numeri casuali su un computer, solo sequenze pseudocasuali basate su un seme. Tuttavia, gli umani sono terribili nell'identificare la casualità, quindi di solito va bene.

+0

lol @ umani che identificano casualità. Grazie per l'aiuto. ^^ – Kyle

7

pseudo-casuale generatori di numeri come Random dovrebbero essere seminate solo volta, quindi:

private static Random _rand = new Random(); 
public static int Roll() 
{ 
    return _rand.Next(1, 100); 
} 

(Nota Feci il valore restituito int anziché void, la funzione Roll come citato in oggetto induce in un errore di sintassi.)

Ma il titolo dice "Creazione di un vero casuale". Random non lo farà per te, è un generatore di numeri pseudo-random, il che significa che è deterministico, solo difficile da prevedere se non conosci il seme. Solitamente è abbastanza buono per la maggior parte degli scopi, ma se hai bisogno della casualità reale , hai bisogno di una fonte di entropia. http://random.org è uno dei più popolari.

+1

Grazie per averlo detto. Stavo riscrivendolo nel thread in base alla memoria, si trattava di un errore di sintassi. Grazie per l'aiuto. – Kyle

Problemi correlati