2009-04-09 19 views
7

¿Cuál es la mejor manera de restringir los valores de un PRNG a un rango menor? Si usa el módulo y el número máximo anterior no es divisible de manera uniforme por el nuevo número máximo, se polariza hacia 0 hasta (old_max - new_max - 1). Asumo la mejor manera sería algo como esto (este punto está flotando, no matemáticas número entero)¿Cuál es el método adecuado para restringir un número pseudoaleatorio a un rango menor?

random_num = PRNG()/max_orginal_range * max_smaller_range 

pero algo en mi interior me hace cuestionar que el método (tal vez flotando diferencias de implementación punto y representación?).

El generador de números aleatorios producirá resultados consistentes en todas las plataformas de hardware y software, y la restricción también lo necesita.

Tenía razón para dudar del pseudocódigo anterior (pero no por las razones que estaba pensando). El answer de MichaelGG me hizo pensar sobre el problema de otra manera. Puedo modelarlo usando números más pequeños y probar cada resultado. Entonces, supongamos que tenemos un PRNG que produce un número aleatorio entre 0 y 31 y desea que el rango más pequeño sea de 0 a 9. Si usa el módulo, se inclina hacia 0, 1, 2 y 3. Si usa el pseudocódigo por encima de usted predispone a 0, 2, 5 y 7. No creo que pueda haber una buena forma de asignar un conjunto al otro. Lo mejor que he logrado hasta ahora es regenerar los números aleatorios que son mayores que old_max/new_max, pero eso también tiene problemas profundos (reduciendo el período, el tiempo para generar nuevos números hasta que uno esté en el rango correcto, etc.) .

Creo que ingenuamente he abordado este problema. Puede ser hora de comenzar una investigación seria sobre la literatura (alguien tiene que haber abordado esto antes).

Respuesta

2

Sé que esta podría no ser una respuesta particularmente útil, pero creo que la mejor manera sería concebir algunos métodos diferentes, probarlos unos pocos millones de veces y verificar los conjuntos de resultados.

En caso de duda, pruébelo usted mismo.

EDITAR

Cabe señalar que muchos lenguajes (como C#) han construido en la limitación de sus funciones

int maximumvalue = 20; 
Random rand = new Random(); 

rand.Next(maximumvalue); 

Y siempre que sea posible, se debe utilizar los más que cualquier código que lo haría escribete a ti mismo No reinventar la rueda.

+0

También puede echar un vistazo a java.util.Random.nextInt (int) que utiliza un método bastante inteligente para restringir el resultado sin introducir un sesgo. Me tomó alrededor de un día para entender por qué funciona, aunque :) – Joey

+0

¿Dónde está disponible esa fuente? (Lo siento, no soy un codificador de Java, no sé nada sobre dónde está la API) – DevinB

+0

La verificación aleatoria no es una buena idea, pero si reduzco los números a algo manejable puedo probar cada resultado (ver arriba), y el pseudocódigo es de hecho parcial. Ahora tengo que ir a buscar artículos que es poco probable que comprenda, suspiro. –

0

Si PRNG() está generando números aleatorios distribuidos uniformemente, lo anterior se ve bien. De hecho (si quiere escalar la media, etc.) lo anterior debería estar bien para todos los propósitos. Supongo que debe preguntar cuál es el error asociado con el PRNG original(), y si una mayor manipulación se agregará a eso sustancialmente.

En caso de duda, generar un conjunto de muestras de tamaño adecuado, y ver los resultados en Excel o similar (para comprobar su media/std.dev etc., para lo que se espera) el acceso

0

Si tiene a una función PRNG (por ejemplo, al azar)() que va a generar números en el rango de 0 < = x < 1, se puede no sólo hacer:

random_num = (int) (random() * max_range); 

para darle los números en el rango de 0 a max_range?

+0

El PRNG en cuestión genera un número entre 0 y 2^32, e incluso si lo hizo, todavía estoy preocupado por la inexactitud del punto flotante que causa problemas entre sistemas (por ejemplo, 1/10 no se puede representar con precisión, por lo que algunas implementaciones eligen .09 .9 y otros .10 ... 01) –

0

Así es como funciona clase aleatoria del CLR cuando se limita (según reflector):

long num = maxValue - minValue; 
if (num <= 0x7fffffffL) { 
    return (((int) (this.Sample() * num)) + minValue); 
} 
return (((int) ((long) (this.GetSampleForLargeRange() * num))) + minValue); 

Incluso si se le ofrece un int positivo, no es difícil llegar a un doble. Simplemente multiplique el int aleatorio por (1/maxint). Pasar de un int de 32 bits a un doble debe proporcionar la precisión adecuada. (Realmente no he probado un PRNG como este, por lo que podría estar perdiendo algo con flotadores.)

+0

Hmm, si estoy leyendo correctamente, el PRNG está generando un flotador (si) o un doble (afuera si). Como los PRNG no producen enteros, lo más probable es que sea real_random/(double) MAX_RANDOM. Entonces la única diferencia es que mi pseudo código asume una base cero y esto permite una base arbitraria. –

+0

Si inspecciona la clase Aleatoria, verá que internamente ("Muestra interna") genera un int, luego se multiplica por 1/Int32.MaxValue (como un doble). El rango GetSampleForLarge solo lo permite con un rango int32 completo. – MichaelGG

+0

Entonces, InternalSample es el real_random y multiplicar por un recíproco es lo mismo que dividir (debe haber una diferencia en la eficiencia). Eso significa que está sesgando los resultados cuando los 2^32 no son divisibles uniformemente por el nuevo rango. Definitivamente parece que no hay forma de evitar el sesgo. –

0

Los generadores de números aleatorios de Psuedo están produciendo esencialmente una serie aleatoria de 1s y 0s, que cuando se añaden entre sí, son un número infinitamente grande en la base dos. cada vez que consumes un poco de tu prng, estás dividiendo ese número entre dos y manteniendo el módulo. Puedes hacer esto para siempre sin desperdiciar ni un solo bit.

Si necesita un número en el rango [0, N), entonces necesita lo mismo, pero en lugar de la base dos, necesita la base N. Es básicamente trivial convertir las bases. Consuma la cantidad de bits que necesita, devuelva el resto de esos bits a su prng para usarlos la próxima vez que necesite un número.

+2

O no entiendo a qué te refieres o sigue siendo parcial. Supongamos un PRNG que genera 0 - 3, queremos reducirlo a 0 - 2. Queremos cuatro números. Es fácil modelar cada caso. Sumando los resultados debería ser igual a 0 - 2. Tenemos que tirar el patrón 11 o se eleva a 1 –

Cuestiones relacionadas