2009-10-08 25 views
5

Necesito un generador pseudoaleatorio que toma un número como entrada y devuelve otro número que es reproducible y parece ser aleatorio.Algoritmo pseudoaleatorio simple

  • Cada número de entrada debe coincidir exactamente con un número de salida y viceversa
  • mismos números de entrada siempre resultar en mismos números de salida
  • números de entrada secuenciales que están muy juntos (por ejemplo. 1 y 2) debe producir números de salida completamente diferentes (por ejemplo, 1 => 9783526, 2 => 283)

No debe ser perfecto, es solo para crear datos de prueba aleatorios pero reproducibles.

Uso C#.


Escribí esta pieza graciosa de código hace algún tiempo que producía algo al azar.

public static long Scramble(long number, long max) 
    { 
    // some random values 
    long[] scramblers = { 3, 5, 7, 31, 343, 2348, 89897 }; 
    number += (max/7) + 6; 
    number %= max; 
    // shuffle according to divisibility 
    foreach (long scrambler in scramblers) 
    { 
     if (scrambler >= max/3) break; 
     number = ((number * scrambler) % max) 
     + ((number * scrambler)/max); 
    } 

    return number % max; 
    } 

Me gustaría tener algo mejor, más confiable, trabajando con cualquier tamaño de número (sin argumento máximo).

¿Podría esto probablemente resolverse usando un algoritmo CRC? O algo de barajar.

+4

Quiere una función hash. – phoku

+0

Duplo de http://stackoverflow.com/questions/239063 – sbi

+0

@sbi: no estoy seguro de que este sea un duplicado exacto, dado el requisito de correspondencia exclusiva entre entrada y salida. Ver el comentario de 'tanascius' en mi respuesta a continuación. – MusiGenesis

Respuesta

2

Usted (tal vez) puede hacer esto fácilmente en C# utilizando la clase Random:

public int GetPseudoRandomNumber(int input) 
{ 
    Random random = new Random(input); 
    return random.Next(); 
} 

Puesto que usted está sembrando explícitamente al azar con la entrada, obtendrá el mismo resultado cada vez que dado el mismo valor de entrada .

+2

Pero su primer requisito es "Cada número de entrada debe coincidir exactamente con un número de salida y viceversa"; el viceversa no funcionará con su solución. – tanascius

+0

@tanascius: en realidad, no estoy seguro de que * no * coincida con este requisito, pero no sé cómo funciona Random bajo el capó, por lo que puede que tengas razón. – MusiGenesis

+1

Bueno, probé las entradas de 1 a 10mio ... nunca se obtiene el mismo resultado dos veces ... por lo que podría funcionar de hecho. Pero aún depende de la implementación y podría cambiar en el futuro. – tanascius

4

elimino el código de Microsoft de esta respuesta, el archivo de código GNU es mucho más largo pero básicamente contiene esto desde http://cs.uccs.edu/~cs591/bufferOverflow/glibc-2.2.4/stdlib/random_r.c:

int32_t val = state[0]; 
val = ((state[0] * 1103515245) + 12345) & 0x7fffffff; 
state[0] = val; 
*result = val; 

para su propósito, la semilla es el estado [0] por lo que sería parecerse más a

int getRand(int val) 
{ 
    return ((val * 1103515245) + 12345) & 0x7fffffff; 
} 
+0

Um, ese aviso de derechos de autor de alguna manera me llama la atención.¿Crees que tienes permiso para pegar ese código aquí? – sbi

+0

bueno, no soy abogado, pero es solo un fragmento del archivo, también dice copyright 1985 - 2001 (es 2009 ahora). También está disponible en línea en otros lugares y dejé el texto de derechos de autor en el archivo. Si alguien tiene un problema con esto, puedo eliminar la respuesta y reemplazarla por la de GNU. –

+0

Este es Steve Ballmer - ¡tu culo es mío, muchacho! – MusiGenesis

1

las dos primeras reglas sugieren una permutación de entrada cabeza de serie, fijo o de la entrada, pero la tercera regla requiere una transformación ulterior.

¿Existe alguna restricción adicional sobre cuáles deberían ser las salidas, para guiar esa transformación? - p.ej. ¿Hay un conjunto de entrada de valores de salida para elegir?

Si la única guía es "no máximo", que haría uso de la siguiente ...

  1. Aplicar un algoritmo hash para toda la entrada para obtener el primer punto de salida. Un CRC podría funcionar, pero para obtener resultados más "aleatorios", use un algoritmo hash de cifrado como MD5.

  2. Use un próximo algoritmo de permutación (muchos enlaces en Google) en la entrada.

  3. Repita la función hash-then-next-permutation hasta que se encuentren todas las salidas necesarias.

El siguiente permutación puede ser excesiva, sin embargo, usted podría probablemente sólo incrementará la primera entrada (y tal vez, en caso de desbordamiento, incremente el segundo y así sucesivamente) antes de volver a hacer el hash.

Para el hashing al estilo criptográfico, necesitará una clave; solo obtenga algo de la entrada antes de comenzar.

1

Un generador de tausworthe es simple de implementar y bastante rápido. El siguiente pseudocódigo aplicación tiene ciclo completo (2 ** 31 - 1, porque el cero es un punto fijo):

def tausworthe(seed) 
    seed ^= seed >> 13 
    seed ^= seed << 18 
    return seed & 0x7fffffff 

No sé C#, pero estoy suponiendo que tiene XOR (^) y el bit desplazamiento (<<, >>) operadores como en C.

Establezca un valor de inicialización e invoque con seed = tausworthe(seed).

Cuestiones relacionadas