semilla - numeros aleatorios c#
¿Por qué parece que mi generador de números aleatorios no es aleatorio en C#? (13)
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 me da la misma respuesta cuando mi min = 0 y max = 1. Obtengo 0 cada vez. (Creé una función de prueba para ejecutarlo, realmente, obtengo 0 cada vez). Me está costando mucho creer que es una coincidencia ... ¿hay algo más que pueda hacer para examinar o probar esto? (Repetí la prueba con min = 0 y max = 10 y las primeras 50 veces, el resultado fue siempre "5", la segunda 50 veces, el resultado fue siempre "9".
?? Necesito algo un poco más consistente al azar ...
-Adeena
Además del problema 0-1 que ya se mencionó en otras respuestas, su problema es real cuando busca un rango de 0-10 y obtiene resultados idénticos 50 veces seguidas.
new Random()
se supone que devuelve un número aleatorio con una semilla inicializada desde el temporizador (segundo actual), pero aparentemente estás llamando a este código 50 veces por segundo. MSDN sugiere: "Para mejorar el rendimiento, cree un Random 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 que está fuera del método, eso debería solucionar su problema de "no aleatoriedad" y mejorar el rendimiento.
Considere también esta publicación para un mejor generador de números pseudoaleatorios que el suministrado por el sistema, si necesita números pseudoaleatorios de "mayor calidad".
Como han mencionado otros, el Random que se construye varias veces por segundo usa el mismo segundo que el valor inicial, así que pondría el constructor de Random fuera de tu bucle 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, por lo que si desea un 0 o 1, debe usar [0,2] como su [mínimo, máximo], o un máximo mayor y luego hacer un binario AND con 1.
public static int RandomOneOrZero(Random random)
{
return random.Next(0, int.MaxValue) & 1;
}
El mínimo es inclusivo, pero el máximo es exclusivo. Echa un vistazo a la API
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.
Encontré una forma muy simple pero efectiva de generar números aleatorios simplemente tomando los últimos dos dígitos de los milisegundos actuales de fecha y hora:
int seed = Convert.ToInt32(DateTime.Now.Millisecond.ToString().Substring(1, 2));
int cnr = new Random(seed).Next(100);
Es crudo, pero funciona! :-)
Por supuesto que generaría estadísticamente el mismo número cada cien veces. Alternativamente, puede tomar los tres dígitos o concatenar con otros valores de fecha y hora, como segundos.
Esa sobrecarga de Next () devuelve:
Un entero con signo de 32 bits mayor o igual que 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. Tal vez quieras random.NextDouble (), que devolverá un doble entre 0 y 1.
Estás malinterpretando la línea "random.Next (min, max)". "min" está en el lugar del número más bajo permitido para ser generado aleatoriamente. Mientras que "max" está en el lugar del número más bajo NO permitido que se genere, no está en el lugar del número más grande permitido para ser dibujado. Entonces, cuando la línea es aleatoria. A continuación (0, 1) básicamente solo estás permitiendo que se dibuje 0.
Este es un addendum 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ática, 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 sin bloqueo que usa un generador para generar 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
}
No cree un método de envoltura para Siguiente. Se desperdicia ciclos creando una nueva instancia de la clase Random. 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 lo son todas las implementaciones), y si crea 100 instancias con la misma semilla, obtendrá 100 instancias de los mismos resultados. Asegúrate de que estás reutilizando la clase.
Además, como ha dicho la gente, tenga en cuenta que MinValue es inclusivo y MaxValue es exclusivo. Para lo que quieras, haz myRand.Next (0, 2).
Siempre Random.Next
0 porque Random.Next
devuelve enteros. Random.NextDouble
llamar a Random.NextDouble
, que devolverá un número entre 0 y 1. Además, debe reutilizar su instancia de Random, como esto:
[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 seguros criptográficamente, use la clase RNGCryptoServiceProvider
; ver este artículo
EDITAR: seguridad del hilo
Varios carteles han declarado 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 conteo de tics, o en el número de milisegundos desde el tiempo de arranque. 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.
en VB siempre comienzo con la función Randomize (). Simplemente llama a Randomize () y luego ejecuta tu función aleatoria. 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! :)
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.