El último post de 2017 fue una pequeña píldora, y el primero de 2018 no podía ser distinto.
A primera vista, crear un número aleatorio puede parecer algo muy sencillo de hacer con C#, ya que tenemos una clase para ello:
https://msdn.microsoft.com/es-es/library/system.random(v=vs.110).aspx
Pero hay que tener una serie de cosas en cuenta para no equivocarnos y creer que estamos generando número aleatorios cuando no es así.
La clase Random no genera números aleatorios, son en realidad «pseudo-aleatorios» ya que dependen de una «semilla» de inicialización. Si no le decimos nada, esta semilla la obtiene automáticamente de la hora del sistema. Por lo tanto, podríamos inicializar la clase random de la siguiente manera:
var random = new Random(); var random = new Random(seed);
Para mostrar algunos errores que se pueden cometer al usar Random veamos como se comporta este código, que a primeras puede parecer un buen generador de número aleatorios:
El resultado que nos da es:
Iteración 0 - semilla 77897968 - valor 0 Iteración 1 - semilla 77897968 - valor 0 Iteración 2 - semilla 77897968 - valor 0 Iteración 3 - semilla 77897968 - valor 0 Iteración 4 - semilla 77897968 - valor 0 Iteración 5 - semilla 77897968 - valor 0 Iteración 6 - semilla 77897968 - valor 0 Iteración 7 - semilla 77897968 - valor 0 Iteración 8 - semilla 77897968 - valor 0 Iteración 9 - semilla 77897968 - valor 0 Iteración 10 - semilla 77897968 - valor 0
No parece muy aleatorio este resultado, ¿verdad?
Como he comentado antes, es importante la semilla con la que inicializamos el Random, ya que de ella dependerá el resultado final, en este caso, aunque estamos generando una nueva instancia de Random en cada iteración, como la semilla no cambia, nos esta generando siempre el mismo número.
Veamos pues como podríamos hacer esto un poco mejor:
Y el resultado:
Iteración 0 - semilla 83354562 - valor 4 Iteración 1 - semilla 83354562 - valor 0 Iteración 2 - semilla 83354562 - valor 2 Iteración 3 - semilla 83354562 - valor 2 Iteración 4 - semilla 83354562 - valor 1 Iteración 5 - semilla 83354562 - valor 2 Iteración 6 - semilla 83354562 - valor 3 Iteración 7 - semilla 83354562 - valor 0 Iteración 8 - semilla 83354562 - valor 1 Iteración 9 - semilla 83354562 - valor 2 Iteración 10 - semilla 83354562 - valor 3
Un poco mejor. Ahora ya parece mas aleatorio. En este caso he generado una única instancia de Random y lo que hago es ir llamando a Next en cada una de las iteraciones. Mucho cuidado con esto, por que como has comprobado, la diferencia es grande.
Si tienes que generar varios números aleatorios asegúrate de crear una única instancia de Random e ir llamando a Next cada vez.
Por otro lado, el otro día probé con un método que genera una semilla distinta no basada en el reloj del sistema que funciona bastante bien, e incluso generando un nuevo Random en cada itearicón me da resultados aleatorios:
Y el resultado:
Iteración 0 - semilla 3583 - valor 2 Iteración 1 - semilla 2564 - valor 1 Iteración 2 - semilla 415 - valor 2 Iteración 3 - semilla 8982 - valor 0 Iteración 4 - semilla 4890 - valor 1 Iteración 5 - semilla 5233 - valor 2 Iteración 6 - semilla 6998 - valor 3 Iteración 7 - semilla 6915 - valor 1 Iteración 8 - semilla 3693 - valor 0 Iteración 9 - semilla 4398 - valor 1 Iteración 10 - semilla 9378 - valor 0
Otra cosa con la que hay que tener cuidado es con los valores de rango a generar con Next, que es el método para devolver el número entero aleatorio. Existen tres sobrecargas del método:
Y la que más se suele usar es pasando un valor máximo, o pasando un mínimo y un máximo.
var randomNumber = new Random().Next(0, 100);
Aquí donde hay que fijarse es en la definición que dice:
Devuelve un entero aleatorio no negativo que es menor que el valor máximo especificado.
Hay que hacer hincapié en lo de menor que el valor máximo.
Por lo tanto en mi ejemplo anterior, se devolverá un valor entre 0 y 99. ¡Cuidado con esto que puede ser causa de errores!
se podría usar el tipo Guid para generar números aleatorios. el siguiente código genera un pin de 6 dígitos:
Guid guid = Guid.NewGuid();
var bytes = guid.ToByteArray();
string hex = BitConverter.ToString(bytes);
hex=hex.Replace(«-«,»»);
//Console.WriteLine(hex);
long decValue = long.Parse(hex.Substring(0,6), System.Globalization.NumberStyles.HexNumber);
decValue=long.Parse(decValue.ToString().Substring(0,6));
Console.WriteLine(decValue);
Si, precisamente tengo un ejemplo parecido en la propia entrada. Lo que pasa es que si quieres un random dentro de un rango concreto, tendrás de usar Random()
Un saludo!
Gracias me re ayudaste con esta explicación.sobre todo por como usarlo con los bucles,ya que eso es lo que ahi es donde sirve para mi..
Lo del número No negativo es raro yo estoy usando godot engine con C# y si devuelve un numero negativo..Nose algo raro hay en esto que estoy haciendo..XD
Oye amigo, no entiendo muy bien el uso de var, que es lo que hace?
En especial esta parte var guid = Guid.NewGuid();
var justNumbers = new
String(guid.ToString().Where(Char.IsDigit).ToArray());
var seed = int.Parse(justNumbers.Substring(0, 4));
Me podrias explicar?
Por cierto tu codigo me sirvio de mucho para una pequeña practica de estudios de tiempos, muchas gracias
Aquí lo explican: https://docs.microsoft.com/es-es/dotnet/csharp/language-reference/keywords/var
como poner números aleatorios en el intervalo de diferentes timer
Muy bien explicado, excelente aporte, me funcionó.
Trataba de obtener dos números aleatorios pero siempre eran iguales.
Me alegro de que te haya sido útil!
como poner números aleatorios en el intervalo de diferentes timer