Perché sembra che il mio generatore di numeri casuali non sia casuale in C #?

Sto lavorando in Microsoft Visual C # 2008 Express.

Ho trovato questo frammento di codice:

public static int RandomNumber(int min, int max) { Random random = new Random(); return random.Next(min, max); } 

il problema è che l’ho eseguito più di 100 volte, ed è SEMPRE a darmi la stessa risposta quando il mio min = 0 e il massimo = 1. Ottengo 0 ogni volta. (Ho creato una funzione di test per eseguirlo – davvero – ricevo 0 ogni volta). Ho difficoltà a credere che sia una coincidenza … c’è qualcos’altro che posso fare per esaminarlo o testarlo? (Ho eseguito nuovamente il test con min = 0 e max = 10 e le prime 50 volte, il risultato era sempre “5”, le seconde volte di 50ish, il risultato era sempre “9”.

?? Ho bisogno di qualcosa di un po ‘più coerentemente casuale

-Adeena

Il problema con min = 0 e max = 1 è che min è inclusivo e max è esclusivo. Quindi l’unico valore ansible per quella combinazione è 0.

 random = new Random(); 

Questo avvia il generatore di numeri casuali con il tempo corrente (in secondi). Quando chiamate la vostra funzione molte volte prima che il clock di sistema cambi, il generatore di numeri casuali viene avviato con lo stesso valore in modo da restituire la stessa sequenza di valori.

Non creare un metodo wrapper per Successivo. Spreca cicli creando una nuova istanza della class Random. Basta usare lo stesso!

 Random myRand = new Random(); for(int i = 0; i < 10; i++) { Console.WriteLine(myRand.Next(0, 10).ToString()); } 

Questo dovrebbe darti dieci valori casuali.

Come è stato detto - Random è pseudo-casuale (come tutte le implementazioni), e se crei 100 istanze con lo stesso seme, otterrai 100 istanze degli stessi risultati. Assicurati di riutilizzare la class.

Inoltre, come si è detto, attenzione che MinValue è inclusivo e MaxValue è esclusivo. Per quello che vuoi, fai myRand.Next (0, 2).

Questo sovraccarico di Next () restituisce:

Un intero con segno a 32 bit maggiore o uguale a minValue e minore di maxValue; ovvero, l’intervallo di valori di ritorno include minValue ma non MaxValue. Se minValue è uguale a maxValue, viene restituito minValue.

0 è l’unico valore ansible per il ritorno. Forse vuoi random.NextDouble (), che restituirà un doppio tra 0 e 1.

Il minimo è inclusivo, ma il massimo è esclusivo. Controlla l’API

Random.Next sempre 0 perché Random.Next restituisce numeri interi. Devi chiamare Random.NextDouble , che restituirà un numero compreso tra 0 e 1. Inoltre, dovresti riutilizzare l’istanza Random, in questo modo:

 [ThreadStatic] static Random random; public static Random Random { get { if (random == null) random = new Random(); return random; } } public static int RandomInteger(int min, int max) { return Random.Next(min, max); } public static double RandomDouble() //Between 0 and 1 { return Random.NextDouble(); } 

Se si desidera crittografare i numeri casuali, utilizzare la class RNGCryptoServiceProvider ; guarda questo articolo

EDIT: sicurezza filo

Oltre al problema 0-1 già rilevato in altre risposte, il tuo problema è reale quando stai cercando un intervallo da 0 a 10 e ottieni risultati identici per 50 volte di seguito.

new Random() dovrebbe restituire un numero casuale con un seme inizializzato dal timer (secondo corrente), ma apparentemente si chiama questo codice 50 volte al secondo. MSDN suggerisce: “Per migliorare le prestazioni, creare un Random per generare molti numeri casuali nel tempo, invece di creare ripetutamente un nuovo casuale per generare un numero casuale.”. Se crei il tuo generatore casuale una volta fuori dal metodo, questo dovrebbe risolvere il tuo problema di “non casualità” oltre a migliorare le prestazioni.

Considera anche questo post per un generatore di numeri pseudo-casuali migliore di quello fornito dal sistema, se hai bisogno di numeri pseudo-casuali di “alta qualità”.

Come altri hanno già detto, il Random che viene costruito più volte al secondo usa lo stesso secondo del seed, quindi metterei il costruttore Random fuori dal tuo loop e passarlo come parametro, come questo:

 public static int RandomNumber(Random random, int min, int max) { return random.Next(min, max); } 

Inoltre, come detto da altri, il massimo è esclusivo, quindi se vuoi uno 0 o 1, dovresti usare [0,2] come [min, max], o un massimo più grande e poi fare un AND binario con 1.

 public static int RandomOneOrZero(Random random) { return random.Next(0, int.MaxValue) & 1; } 

Questo è un addendum a qualsiasi risposta, poiché la risposta a questa domanda specifica è che i limiti dovrebbero essere (0, 2) non (0, 1).

Tuttavia, se si desidera utilizzare un metodo wrapper statico, è necessario ricordare che Random non è thread-safe, quindi è necessario fornire il proprio meccanismo di sincronizzazione o fornire un’istanza per-thread. Ecco un’implementazione in gran parte non bloccante che utilizza un generatore per seminare ogni generatore per thread:

 public static class ThreadSafeRandom { private static readonly Random seed = new Random(); [ThreadStatic] private static Random random; public static int Next(int min, int max) { if (random == null) { lock (seed) { random = new Random(seed.Next()); } } return random.Next(min, max); } // etc. for other members } 

Stai fraintendendo la frase “random.Next (min, max)”. “min” è nel posto del numero più basso che può essere generato casualmente. Mentre “max” è nel posto del numero più basso che NON è stato permesso di generare non è nel posto del numero più grande che è permesso di essere estratto. Quindi quando la linea è casuale. Avanti (0, 1) in pratica stai solo permettendo che 0 sia disegnato.

Diversi poster hanno dichiarato che Random () utilizza un seme basato sul secondo corrente dell’orologio di sistema e qualsiasi altra istanza di Random creata nello stesso secondo avrà lo stesso seme. Questo non è corretto Il seed per il costruttore senza parametri di Random si basa sul conteggio delle tacche o sul numero di millisecondi dal momento dell’avvio. Questo valore viene aggiornato sulla maggior parte dei sistemi circa ogni 15 millisecondi, ma può variare in base all’hardware e alle impostazioni di sistema.

Ho trovato un modo molto semplice, ma efficace per generare numeri casuali semplicemente prendendo le ultime due cifre degli attuali millisecondi datetime:

  int seed = Convert.ToInt32(DateTime.Now.Millisecond.ToString().Substring(1, 2)); int cnr = new Random(seed).Next(100); 

È grezzo, ma funziona! 🙂

Ovviamente genererebbe statisticamente lo stesso numero ogni cento volte. In alternativa, puoi prendere tutte e tre le cifre o concatenare con altri valori datetime come secondi circa.

in VB inizio sempre con la funzione Randomize (). Basta chiamare Randomize () quindi eseguire la funzione casuale. Faccio anche quanto segue:

 Function RandomInt(ByVal lower As Integer, ByVal upper As Integer) As Integer Return CInt(Int((upper - lower + 1) * Rnd() + lower)) End Function 

Spero che questo ti aiuti! 🙂