2010-02-14 57 views
11

Estoy buscando generar un número aleatorio entre 1 y 5 millones. El proceso no tiene que ser rápido (aunque sería bueno si lo fuera), pero debe ser lo más aleatorio posible (sé que nada es aleatorio). Tengo una variedad de fuentes de datos para la semilla.Números aleatorios usando C#

No estoy seguro de si la clase .NETRandom va a ser suficiente para esto.

Esto se utilizará para seleccionar un boleto ganador.

+5

Defina con claridad y precisión "lo más aleatorio posible". Para obtener una señal que es en realidad "lo más aleatoria posible", necesita una fuente de entropía, la semilla, que tiene más bits de entropía que el elemento aleatorio generado a partir de esa semilla. Entonces, si ya tiene una variedad de fuentes de datos para la semilla, y son de alta entropía, entonces ya está listo. Simplemente extraiga 24 bits de su fuente de entropía, y eso le da un número entre 0 y 16 millones que es ** lo más aleatorio posible dada su fuente de entropía **. –

+2

Además, sería tremendamente útil si describiera para qué va a utilizar este número aleatorio. –

+3

Re: su actualización: ahora ya no está en el ámbito únicamente de las matemáticas y la tecnología, sino en el ámbito de las regulaciones legales. La mayoría de las personas que leen esto no son abogados familiarizados con las leyes sobre qué características debe poseer un dispositivo que elige el ganador de una lotería. Recomendaría consultar con un abogado y un estadístico antes de dedicar más tiempo a buscar una solución técnica. Ciertamente, ninguna solución * simple * "pseudo aleatoria" será aceptable; uno puede calcular fácilmente cuál es el próximo número ganador de los anteriores con un PRNG. –

Respuesta

17

La clase System.Random probablemente es lo suficientemente bueno:

números

pseudo-aleatorios se eligen con la misma probabilidad de un conjunto finito de números. Los números elegidos no son completamente aleatorios porque se usa un algoritmo matemático definido para seleccionarlos, pero son lo suficientemente aleatorios para fines prácticos. La implementación actual de la clase Random se basa en el algoritmo generador de números aleatorios sustractivos de Donald E. Knuth. Para obtener más información, vea D. E. Knuth. "El arte de la programación de computadoras, volumen 2: Algoritmos de Seminumerical". Addison-Wesley, Reading, MA, segunda edición, 1981.

La única cosa que hay que tener en cuenta es que no emplee la misma semilla con demasiada frecuencia:

Si el mismo la semilla se usa repetidamente, se genera la misma serie de números. Una forma de producir secuencias diferentes es hacer que el valor inicial sea dependiente del tiempo, produciendo así una serie diferente con cada instancia nueva de Aleatorio.

+1

Vea aquí http://connect.microsoft.com/VisualStudio/feedback/details/634761/system -random-serious-bug Está codificado incorrectamente y por lo tanto no es lo suficientemente bueno – evolvedmicrobe

+0

@evolvedmicrobe: Después de ejecutar un montón de pruebas estadísticas en una versión de 'System.Random' con un parche que soluciona ese error en particular, no está claro para mí que no hay otras cosas sobre el RNG que deberían ser más preocupantes. Ciertamente, tiene varios problemas diferentes: https://github.com/dotnet/corefx/issues/23298 – fuglede

7

Si necesita un número aleatorio criptográfico, vaya a la clase System.Security.Cryptography.RNGCryptoServiceProvider o utilice el método de fábrica RandomNumberGenerator.Create() para crear el generador de números aleatorios configurado por defecto.

+3

RNGCryptServiceProvider trabaja en llenar matrices de bytes por lo que necesitaría volver a convertirlo en un int y comprobar que está en el rango correcto – zebrabox

+1

+1 para el comentario de @ zebrabox, más: si el valor generado está fuera de rango, NO modifíquelo (% operador) ya que eso puede causar un sesgo para algunos valores. Da un rodeo y genera otro valor en su lugar. – devstuff

+0

@devstuff Cuál es una razón más para no usar 'System.Random' ya que su implementación de' Next (...) 'está sesgada (No parecen usar'% 'pero los números no son igualmente probables). – CodesInChaos

0

aleatoria de .NET debe estar bien para esto:

var random = new Random(System.DateTime.Now.Millisecond); 

int randomNumber = random.Next(1, 5000000); 
+1

Esto solo funciona para una variable local, es un accidente que está por ocurrir. –

+0

Debe ser int randomNumber = random.Next (1, 5000001); como el método .Net devuelve un número que incluye el límite inferior pero excluye el límite superior. –

+0

Depende del contexto donde se usa el número si un milisegundo es una semilla suficientemente buena. Las máquinas tragamonedas han sido pirateadas de esta manera. – Paco

5

Ver el blog de Jon Skeet Revisiting Randomness una muy buena crítica de cómo utilizar la aleatoriedad:

Revisando aleatoriedad
Casi todas las preguntas de desbordamiento de pila, que incluye las palabras "al azar" y "repiten "tiene la misma respuesta básica. Es una de las "trampas" más comunes en .NET, Java, y sin duda otros plataformas: la creación de un nuevo generador de números aleatorios sin especificar una semilla dependerá de la corriente instante de tiempo. La hora actual como medida por el ordenador no cambio muy a menudo comparada con la forma frecuencia con la que puede crear y utilizar un generador de números aleatorios - por lo código que crea repetidamente una nueva instancia de aleatorio y lo utiliza una vez terminará hasta mostrando mucha repetición.

more...

+0

"más ..." el enlace ahora está roto. –

1

Si usted está buscando verdaderos números aleatorios, entonces debería considerar el uso de un generador de números aleatorios en línea que utiliza fenómeno natural, como http://www.random.org, que utiliza el ruido atmosférico. Los verdaderos números aleatorios también son buenas semillas para generadores de números aleatorios psuedo.

Sipwiz muestra cómo usarlo en C# en su respuesta: Generate random values in C#. También se discute aquí: http://www.vcskicks.com/random-number-generator.php.

Hay muchos ángulos en los generadores de números aleatorios. Una implementación alternativa interesante es ISSAC (ttp: //burtleburtle.net/bob/rand/isaac.html), que también contiene una buena discusión sobre el sesgo y demás, y también hay una versión de C# (http://burtleburtle.net/bob/rand/isaacafa.html).

5

Hubo un artículo realmente bueno que leí recientemente sobre diferentes tipos de PRNG y cómo les va en términos de varias pruebas de aleatoriedad diferentes. Desafortunadamente, parece que no puedo encontrarlo ahora. La esencia de esto, sin embargo, era que los generadores de números aleatorios predeterminados en casi todos los lenguajes de programación populares son bastante ingenuos y tienen sesgos bastante significativos.

Otra respuesta ya menciona que no hay ningún PRNG, sin importar cuán sofisticado sea el algoritmo, es lo suficientemente bueno para aplicaciones criptográficas. Esto es verdad. Como mencionas que esto se usará para "seleccionar un ticket ganador", ignorémoslo por el momento.

El algoritmo Knuth utilizado por la clase .NET System.Random está optimizado principalmente para la distribución de velocidad, no aleatoria. Es "lo suficientemente aleatorio" para muchos propósitos, de los cuales la mayoría de las aplicaciones nunca se alejan demasiado, pero en los campos de (a) juegos y (b) simulación estadística, la mayoría de la gente parece pensar que es una mala elección. Es mejor que los LCG que solían ser los predeterminados en las bibliotecas antiguas, pero aún así no desea utilizarlo para algo así como una lotería.

No te dejes engañar pensando que solo usas una fuente criptográfica. El problema con los RNG criptográficos es que llenan una secuencia de bytes, pero convertir esto en un único entero aleatorio entre x y y requiere que haga aritmética modular (o redondeo, el mismo resultado de cualquier manera). Y si su rango aleatorio no se divide perfectamente en cualquier potencia de 2 definida por la longitud del byte, entonces va a terminar con un sesgo en los números más bajos. Los datos generados tienen alta entropía, pero su resultado estará sesgado.

Como un simple ejemplo, digamos que obtienes un número aleatorio "perfecto" de 1 a 10 y ahora quieres convertirlo en un número aleatorio entre 1 y 7. ¿Cómo lo haces? Simplemente calculando result % 7 estará muy predispuesto hacia los números 1-3. Hay algunas maneras de reducir el sesgo al usar un RNG criptográfico, pero el punto que estoy tratando de plantear es que los RNG criptográficos están diseñados para aplicaciones criptográficas, y usar uno de esos para una simulación de Monte Carlo no suele ser la mejor idea.

Hasta donde yo sé, el PRNG "bueno" más popular actualmente, que se usa comúnmente en aplicaciones de juegos, es el Mersenne Twister. Hay un .NET implementation here. Este algoritmo pasa todos los Diehard Tests para distribución aleatoria; muestra casi ningún sesgo y es una buena opción cuando usa números aleatorios para aplicaciones probabilísticas y estadísticas.

La Biblioteca Científica GNU también tiene un número de RNG algorithms y, como era de esperar, el Mersenne Twister se encuentra en la parte superior de la lista.Sin embargo, vale la pena mirar algunas de las otras por curiosidad; RANLUX también puntúa bastante alto en la prueba de dietas IIRC.

Eric tiene razón con su comentario, por supuesto; toda esta información es en vano si no tiene requisitos técnicos específicos sobre "qué tan aleatorio" necesita que sean sus números aleatorios. Estoy usando una definición que sería aplicable a una aplicación de juego/juegos de azar de impacto relativamente bajo (es decir, no es un sitio de juego registrado importante con millones de visitantes por día; existen reglas más estrictas sobre la aleatoriedad para ellos).

+0

La biblioteca de C# no se basa en el método de Knuth, que metió la pata de codificación que – evolvedmicrobe

+0

@evolvedmicrobe: [Eso es lo que dice su documentación] (http://msdn.microsoft.com/en-us/library/system.random (v = v .110) .aspx). ¿Tiene una cita o alguna evidencia para demostrar lo contrario? – Aaronaught

+0

sí, lo intentaron aquí y me he verificado por descompilación: http://connect.microsoft.com/VisualStudio/feedback/details/634761/system-random-serious-bug – evolvedmicrobe

3

Para generar un número aleatorio, cree un objeto de clase Random y luego use la función Next de este objeto para generar un número aleatorio. Tiene muchas sobrecargas como:

Next(int minimum, int maximum); 
Next(int Maximum); 

donde puede especificar el rango mínimo y máximo entre el cual desea el número aleatorio.

Fragmento de código:

Random random = new Random(); 
int maxValue = 100; 

int r = random.Next(maxValue); 
3

clase El System.Random es muy problemático y no es un buen ajuste con el requisito. En teoría, debería proporcionar mejores resultados que muchos otros generadores pseudoaleatorios. Es un puerto directo y literal del código de ejemplo C para un Generador de Fibonacci Lagged (LFG) provisto en la página 283 de la segunda edición de 'Recetas Numéricas en C' (el código fue reescrito en ediciones posteriores). Los LFG usan un algoritmo mejor que los Generadores Congruenciales Lineales (LCG) usados ​​en muchas otras bibliotecas (por ejemplo, Java).

Desafortunadamente, la implementación de Microsoft de la clase System.Random tiene un error. Consulte http://connect.microsoft.com/VisualStudio/feedback/details/634761/system-random-serious-bug para obtener más información. Parece que alguien tecleó accidentalmente en '21' cuando tenía la intención de escribir '31'. Esto compromete las características pseudoaleatorias del algoritmo. El enlace incluye una explicación de MS sobre por qué se sienten incapaces de corregir el error en esta etapa.

+0

Gracias por la respuesta detallada. Terminamos usando un hardware rng pero gracias por la información y el enlace! – LiamB