c# - usar - metodo random en visual studio
RNGCryptoServiceProvider-Revisión de números aleatorios (7)
Bueno, el uso de RNGCryptoServiceProvider
te da una semilla de fuerza de cifrado no presumible, mientras que Environment.TickCount
es, en teoría, predecible.
Otra diferencia crucial sería evidente al llamar a su método NextInt
varias veces en rápida sucesión. El uso de RNGCryptoServiceProvider
generará el objeto Random
con un número de fuerza de cifrado diferente cada vez, lo que significa que continuará para devolver un número aleatorio diferente para cada llamada. El uso de TickCount
corre el riesgo de sembrar el objeto Random
con el mismo número cada vez (si se llama al método varias veces durante el mismo "tick"), lo que significa que continuará para devolver el mismo número (supuestamente aleatorio) para cada llamada.
Si realmente necesita números verdaderamente aleatorios, entonces no debería usar una computadora para generarlos: debería medir la desintegración radioactiva o algo similar, realmente impredecible.
Mientras buscaba los mejores intentos de generar números verdaderamente aleatorios, me topé con este ejemplo de código.
Buscando opiniones sobre este fragmento.
using System;
using System.Security.Cryptography;
private static int NextInt(int min, int max)
{
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
byte[] buffer = new byte[4];
rng.GetBytes(buffer);
int result = BitConverter.ToInt32(buffer, 0);
return new Random(result).Next(min, max);
}
Fuente: http://www.vcskicks.com/code-snippet/rng-int.php
¿Se preferiría esto a usar una semilla de conteo de garrapatas como:
Random rand = new Random(Environment.TickCount);
rand.Next(min, max);
Nota:
No estoy buscando proveedores de datos aleatorios de terceros, como Random.org , ya que dicha dependencia no es realista para la aplicación.
Creo que este es un generador más eficiente y posiblemente más rápido que los mencionados anteriormente.
public static class SecureRandom
{
#region Constants
private const int INT_SIZE = 4;
private const int INT64_SIZE = 8;
#endregion
#region Fields
private static RandomNumberGenerator _Random;
#endregion
#region Constructor
static SecureRandom()
{
_Random = new RNGCryptoServiceProvider();
}
#endregion
#region Random Int32
/// <summary>
/// Get the next random integer
/// </summary>
/// <returns>Random [Int32]</returns>
public static Int32 Next()
{
byte[] data = new byte[INT_SIZE];
Int32[] result = new Int32[1];
_Random.GetBytes(data);
Buffer.BlockCopy(data, 0, result, 0, INT_SIZE);
return result[0];
}
/// <summary>
/// Get the next random integer to a maximum value
/// </summary>
/// <param name="MaxValue">Maximum value</param>
/// <returns>Random [Int32]</returns>
public static Int32 Next(Int32 MaxValue)
{
Int32 result = 0;
do
{
result = Next();
} while (result > MaxValue);
return result;
}
#endregion
#region Random UInt32
/// <summary>
/// Get the next random unsigned integer
/// </summary>
/// <returns>Random [UInt32]</returns>
public static UInt32 NextUInt()
{
byte[] data = new byte[INT_SIZE];
Int32[] result = new Int32[1];
do
{
_Random.GetBytes(data);
Buffer.BlockCopy(data, 0, result, 0, INT_SIZE);
} while (result[0] < 0);
return (UInt32)result[0];
}
/// <summary>
/// Get the next random unsigned integer to a maximum value
/// </summary>
/// <param name="MaxValue">Maximum value</param>
/// <returns>Random [UInt32]</returns>
public static UInt32 NextUInt(UInt32 MaxValue)
{
UInt32 result = 0;
do
{
result = NextUInt();
} while (result > MaxValue);
return result;
}
#endregion
#region Random Int64
/// <summary>
/// Get the next random integer
/// </summary>
/// <returns>Random [Int32]</returns>
public static Int64 NextLong()
{
byte[] data = new byte[INT64_SIZE];
Int64[] result = new Int64[1];
_Random.GetBytes(data);
Buffer.BlockCopy(data, 0, result, 0, INT64_SIZE);
return result[0];
}
/// <summary>
/// Get the next random unsigned long to a maximum value
/// </summary>
/// <param name="MaxValue">Maximum value</param>
/// <returns>Random [UInt64]</returns>
public static Int64 NextLong(Int64 MaxValue)
{
Int64 result = 0;
do
{
result = NextLong();
} while (result > MaxValue);
return result;
}
#endregion
#region Random UInt32
/// <summary>
/// Get the next random unsigned long
/// </summary>
/// <returns>Random [UInt64]</returns>
public static UInt64 NextULong()
{
byte[] data = new byte[INT64_SIZE];
Int64[] result = new Int64[1];
do
{
_Random.GetBytes(data);
Buffer.BlockCopy(data, 0, result, 0, INT64_SIZE);
} while (result[0] < 0);
return (UInt64)result[0];
}
/// <summary>
/// Get the next random unsigned long to a maximum value
/// </summary>
/// <param name="MaxValue">Maximum value</param>
/// <returns>Random [UInt64]</returns>
public static UInt64 NextULong(UInt64 MaxValue)
{
UInt64 result = 0;
do
{
result = NextULong();
} while (result > MaxValue);
return result;
}
#endregion
#region Random Bytes
/// <summary>
/// Get random bytes
/// </summary>
/// <param name="data">Random [byte array]</param>
public static byte[] NextBytes(long Size)
{
byte[] data = new byte[Size];
_Random.GetBytes(data);
return data;
}
#endregion
}
De acuerdo, llego un poco tarde a la fiesta, pero realmente quería una implementación completa de System.Random que pueda llamarse varias veces durante el mismo tic del temporizador y que produzca resultados diferentes. Después de agonizar mucho sobre diferentes implementaciones, me decidí por la más simple que se me ocurrió, que proporciona un constructor predeterminado que proporciona una clave aleatoria al constructor básico de System.Random:
/// <summary> An implementation of System.Random whose default constructor uses a random seed value rather than the system time. </summary>
public class RandomEx : Random
{
/// <summary> Initializes a new CryptoRandom instance using a random seed value. </summary>
public RandomEx()
: base(_GetSeed())
{ }
/// <summary> Initializes a new CryptoRandom instance using the specified seed value. </summary>
/// <param name="seed"> The seed value. </param>
public RandomEx(int seed)
: base(seed)
{ }
// The static (shared by all callers!) RandomNumberGenerator instance
private static RandomNumberGenerator _rng = null;
/// <summary> Static method that returns a random integer. </summary>
private static int _GetSeed()
{
var seed = new byte[sizeof(int)];
lock (typeof(RandomEx)) {
// Initialize the RandomNumberGenerator instance if necessary
if (_rng == null) _rng = new RNGCryptoServiceProvider();
// Get the random bytes
_rng.GetBytes(seed);
}
// Convert the bytes to an int
return BitConverter.ToInt32(seed, 0);
}
}
En el camino, también escribí y probé una implementación que anula los métodos necesarios para usar RNGCryptoServiceProvider para proporcionar TODOS los valores aleatorios (en lugar de confiar en cualquier generador de números aleatorios incluido en la clase System.Random). Pero no tengo idea de cuán criptográficamente fuertes son los resultados para cuando tomas mis valores aleatorios de Muestra () y los empujas a través de las transformaciones para producir valores enteros. De todos modos, aquí está el código si alguien lo quiere:
/// <summary> An implementation of System.Random that uses RNGCryptoServiceProvider to provide random values. </summary>
public class CryptoRandom : Random, IDisposable
{
// Class data
RandomNumberGenerator _csp = new RNGCryptoServiceProvider();
/// <summary> Returns a random number between 0.0 (inclusive) and 1.0 (exclusive). </summary>
protected override double Sample()
{
// Get a nonnegative random Int64
byte[] bytes = new byte[sizeof(long)];
_csp.GetBytes(bytes);
long value = BitConverter.ToInt64(bytes, 0) & long.MaxValue;
// Scale it to 0->1
return (double)value / (((double)Int64.MaxValue) + 1025.0d);
}
/// <summary> Fills the elements of the specified array of bytes with random numbers. </summary>
/// <param name="buffer"> An array of bytes to contain random numbers. </param>
public override void NextBytes(byte[] buffer)
{
_csp.GetBytes(buffer);
}
/// <summary> Returns a nonnegative random integer. </summary>
/// <returns> A 32-bit signed integer greater than or equal to zero. </returns>
public override int Next()
{
byte[] data = new byte[4];
_csp.GetBytes(data);
data[3] &= 0x7f;
return BitConverter.ToInt32(data, 0);
}
/// <summary> Returns a random integer that is within a specified range. </summary>
/// <param name="minValue"> The inclusive lower bound of the random number returned. </param>
/// <param name="maxValue"> The exclusive upper bound of the random number returned. maxValue must be greater than or equal to minValue. </param>
/// <returns> A 32-bit signed integer greater than or equal to minValue and less than maxValue; that is, the range of return values includes minValue but not maxValue. If minValue equals maxValue, minValue is returned. </returns>
public override int Next(int minValue, int maxValue)
{
// Special case
if (minValue == maxValue) return minValue;
double sample = Sample();
double range = (double)maxValue - (double)minValue;
return (int)((sample * (double)range) + (double)minValue);
}
#region IDisposible implementation
/// <summary> Disposes the CryptoRandom instance and all of its allocated resources. </summary>
public void Dispose()
{
// Do the actual work
Dispose(true);
// This object will be cleaned up by the Dispose method. Call GC.SupressFinalize to
// take this object off the finalization queue and prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}
// Dispose(bool disposing) executes in two distinct scenarios:
//
// If disposing is true, the method has been called directly or indirectly by a user''s code and both
// managed and unmanaged resources can be disposed.
//
// If disposing is false, the method has been called by the runtime from inside the finalizer.
// In this case, only unmanaged resources can be disposed.
protected virtual void Dispose(bool disposing)
{
if (disposing) {
// The method has been called directly or indirectly by a user''s code; dispose managed resources (if any)
if (_csp != null) {
_csp.Dispose();
_csp = null;
}
// Dispose unmanaged resources (if any)
}
}
#endregion
}
Hice una pregunta similar hace 2 años :) revisa y ve si te ayuda. Utilicé ese código para generar un número aleatorio seguro para el procesamiento de pagos.
No uses tu código. Su solución es incorrecta y genera números aleatorios pobres. Sugiero mi solución, que genera números aleatorios criptográficamente fuertes:
public class SecureRandom : RandomNumberGenerator
{
private readonly RandomNumberGenerator rng = new RNGCryptoServiceProvider();
public int Next()
{
var data = new byte[sizeof(int)];
rng.GetBytes(data);
return BitConverter.ToInt32(data, 0) & (int.MaxValue - 1);
}
public int Next(int maxValue)
{
return Next(0, maxValue);
}
public int Next(int minValue, int maxValue)
{
if (minValue > maxValue)
{
throw new ArgumentOutOfRangeException();
}
return (int)Math.Floor((minValue + ((double)maxValue - minValue) * NextDouble()));
}
public double NextDouble()
{
var data = new byte[sizeof(uint)];
rng.GetBytes(data);
var randUint = BitConverter.ToUInt32(data, 0);
return randUint / (uint.MaxValue + 1.0);
}
public override void GetBytes(byte[] data)
{
rng.GetBytes(data);
}
public override void GetNonZeroBytes(byte[] data)
{
rng.GetNonZeroBytes(data);
}
}
Realmente depende del uso previsto o el requisito del número aleatorio que se genera.
La clase Random es útil para la aleatorización práctica como la aleatorización del orden en que se muestran las imágenes en un rotador de imágenes o rollos de un dado.
Si, por otro lado, necesita números aleatorios que requieran una mayor cantidad de seguridad, como para generar una contraseña o una clave de confirmación de pago, entonces utilice una clase como RNGCryptoServiceProvider o cree su propia implementación de la clase abstracta RandomNumberGenerator que implementa un algoritmo criptográfico Son mejores alternativas.
Realmente no sugiero usar el ejemplo proporcionado. A pesar de que RNGCryptoServiceProvider devuelve un aleatorio realmente bueno (o al menos debería), pero lo mismo no es cierto para Random. Más sobre - no se sabe si Random (valor) crea una verdadera bijección contra el valor reajustado por Siguiente (..). Más aún: no se garantiza que Next (min, max) devuelva el valor de una manera verdaderamente aleatoria (lo que significa iguales oportunidades para que el número alcance cada valor).
Primero eliminaría el problema para obtener el número en el intervalo 0 - máx (exclusivo). Entonces usaría la potencia más cercana de 2 para obtener un valor aleatorio en el rango 0 - (2 ^ n - 1). Ahora, una cosa que NO DEBES hacer aquí es usar módulo para obtener el número en el rango preferido como rand (0 - (2 ^ n - 1))% max, porque al hacerlo tienes más posibilidades de obtener un número en el rango inferior.
Ejemplo: max = 3, n = 2 (0 - (2 ^ 2 - 1))% 2, números (0, 1, 2, 3), valores correspondientes después de módulo (0, 1, 2, 0). Mira que golpeamos 0 dos veces, lo cual es realmente malo aleatorio.
Entonces, la solución sería usar crypto random para obtener el valor más cercano a la potencia de dos y, en caso de que el valor esté fuera del rango máximo, repita el procedimiento (obtenga otro crypto random) hasta que el valor esté dentro del rango dado. Esto sería mucho mejor algoritmo.