¿Por qué parece que mi generador de números aleatorios no es aleatorio en C #?

Estoy trabajando en Microsoft Visual C # 2008 Express.

Encontré este fragmento de código:

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

el problema es que lo he ejecutado más de 100 veces, y SIEMPRE estoy dándome la misma respuesta cuando mi mínimo = 0 y máximo = 1. Obtuve 0 cada vez. (Creé una función de prueba para ejecutarla, en realidad, obtengo 0 cada vez). Estoy teniendo dificultades para creer que es una coincidencia … ¿hay algo más que pueda hacer para examinar o probar esto? (Volví a ejecutar la prueba con min = 0 y max = 10 y las primeras 50 veces, el resultado fue siempre “5”, el segundo 50 veces, el resultado fue siempre “9”.

?? Necesito algo un poco más aleatorio …

-Adeena

El problema con min = 0 y max = 1 es que min es inclusivo y max es exclusivo. Entonces, el único valor posible para esa combinación es 0.

 random = new Random(); 

Esto inicia el generador de números aleatorios con la hora actual (en segundos). Cuando llama a su función muchas veces antes de que cambie el reloj del sistema, el generador de números aleatorios se inicia con el mismo valor, por lo que devuelve la misma secuencia de valores.

No crees un método de envoltura para Siguiente. Desperdicia ciclos creando una nueva instancia de la clase Aleatoria. Solo usa el mismo!

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

Eso debería darte diez valores aleatorios.

Como se ha dicho, Random es pseudoaleatorio (como todas las implementaciones), y si crea 100 instancias con la misma semilla, obtendrá 100 instancias de los mismos resultados. Asegúrate de reutilizar la clase.

Además, como han dicho las personas, tenga en cuenta que MinValue es inclusivo y MaxValue es exclusivo. Para lo que quieras, haz myRand.Next (0, 2).

Esa sobrecarga de Next () devuelve:

Un entero de 32 bits con signo mayor que o igual a minValue y menor que maxValue; es decir, el rango de valores de retorno incluye minValue pero no MaxValue. Si minValue es igual a maxValue, se devuelve minValue.

0 es el único valor posible para que regrese. Quizás desee random.NextDouble (), que devolverá un doble entre 0 y 1.

El min es inclusivo, pero el máximo es exclusivo. Mira la API

Siempre Random.Next 0 porque Random.Next devuelve enteros. Debes llamar a Random.NextDouble , que devolverá un número entre 0 y 1. Además, debes reutilizar tu instancia de Random, así:

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

Si desea números aleatorios criptográficamente seguros, use la clase RNGCryptoServiceProvider ; ver este artículo

EDITAR: hilo de seguridad

Además del problema 0-1 ya mencionado en otras respuestas, su problema es real cuando busca un rango de 0-10 y obtiene resultados idénticos 50 veces seguidas.

Se supone que new Random() devolverá un número aleatorio con una inicialización inicial del temporizador (segundo actual), pero aparentemente está llamando a este código 50 veces por segundo. MSDN sugiere: “Para mejorar el rendimiento, crea un Aleatorio para generar muchos números aleatorios a lo largo del tiempo, en lugar de crear repetidamente un nuevo Random para generar un número aleatorio”. Si crea su generador aleatorio una vez fuera del método, eso debería solucionar su problema de “no aleatoriedad” así como también mejorar el rendimiento.

También considere esta publicación como un mejor generador de números pseudoaleatorios que el suministrado por el sistema, si necesita números pseudoaleatorios de “calidad superior”.

Como otros han mencionado, el Random que se construye varias veces por segundo usa el mismo segundo que el seed, por lo que pondría el constructor Random fuera de su loop, y lo pasaría como un parámetro, como este:

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

También como lo mencionaron otros, el máximo es exclusivo, así que si quieres un 0 o 1, debes usar [0,2] como tu [mín, máx], o un máximo mayor y luego hacer un Y binario con 1.

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

Este es un apéndice a cualquier respuesta, ya que la respuesta a esta pregunta específica es que los límites deben ser (0, 2) no (0, 1).

Sin embargo, si desea utilizar un método de envoltura estático, debe recordar que Random no es seguro para subprocesos, por lo que debe proporcionar su propio mecanismo de sincronización o proporcionar una instancia por subproceso. Aquí hay una implementación en gran parte no bloqueante que usa un generador para sembrar cada generador por hilo:

 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 } 

Estás malinterpretando la línea “random.Next (min, max)”. “min” está en el lugar del número más bajo permitido generar al azar. Mientras que “max” está en el lugar del número más bajo que NO se permite generar, no está en el lugar donde se dibujó el número más grande permitido. Entonces, cuando la línea es aleatoria. Luego (0, 1) básicamente solo permite que se dibuje 0.

Varios carteles han afirmado que Random () usa una semilla basada en el segundo actual en el reloj del sistema y cualquier otra instancia de Random creada en el mismo segundo tendrá la misma semilla. Esto es incorrecto. La semilla para el constructor sin parámetros de Random se basa en el recuento de ticks, o número de milisegundos desde el momento del inicio. Este valor se actualiza en la mayoría de los sistemas aproximadamente cada 15 milisegundos, pero puede variar según el hardware y la configuración del sistema.

Encontré una manera muy simple pero efectiva de generar números aleatorios simplemente tomando los últimos dos dígitos de los milisegundos actuales de datetime:

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

Es crudo, pero funciona! 🙂

Por supuesto generaría estadísticamente el mismo número cada cien veces. De forma alternativa, puede tomar los tres dígitos o concatenar con otros valores de fecha y hora como segundos aproximadamente.

en VB siempre comienzo con la función Aleatorizar (). Simplemente llame a Randomize () y luego ejecute su función aleatoria. Yo también hago lo siguiente:

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

¡Espero que esto ayude! 🙂