2011-04-03 14 views
16

Necesito ayuda con un generador de números aleatorios que estoy creando. Mi código es el siguiente (dentro de una clase llamados números):Java aleatorio siempre devuelve el mismo número cuando configuro la semilla?

public int random(int i){ 
    Random randnum = new Random(); 
    randnum.setSeed(123456789); 
    return randnum.nextInt(i); 
} 

Cuando llamo a este método de otra clase (con el fin de generar un número aleatorio), que devuelve siempre el mismo número. Por ejemplo, si tuviera que hacer:

System.out.println(numbers.random(10)); 
System.out.print(numbers.random(10)); 

siempre imprime el mismo número, por ejemplo, 5 5. ¿Qué debo hacer para que se impriman dos números diferentes, p. 5 8

Es obligatorio que establezca la semilla.

Gracias

+3

No cree un nuevo objeto aleatorio cada vez que llame a la función. Guárdelo como una variable privada y ejemplínelo solo una vez – Rob

+0

¿A qué le está asignando la semilla? –

+0

No se recomienda configurar manualmente la semilla a menos que sepa exactamente lo que significa. – m0skit0

Respuesta

36

tiene que compartir la instancia Random() través de toda la clase:

public class Numbers { 
    Random randnum; 

    public Numbers() { 
     randnum = new Random(); 
     randnum.setSeed(123456789); 
    } 

    public int random(int i){ 
     return randnum.nextInt(i); 
    } 
} 
32

Si siempre configura la semilla, siempre obtendrá la misma respuesta. Eso es lo que hace el establecimiento de la semilla.

3

Establezca la semilla una vez en el inicio, en lugar de cada vez que desee un nuevo número aleatorio.

2

Lo que está utilizando no es un generador de números aleatorios, que es un generador de números pseudo-aleatoria. Los generadores de PRNG generan secuencias de números pseudoaleatorias, la semilla selecciona un punto de inicio en una secuencia (un PRNG puede generar una o varias secuencias).

1

Normalmente, Random no es realmente aleatorio sino pseudoaleatorio. Significa que toma una semilla dada y la usa para generar una secuencia de números que parece aleatoria (pero es totalmente predecible y se repite si se pone la misma semilla).

Si no pone semilla, la primera semilla se tomará de una fuente variable (generalmente la hora del sistema).

Normalmente, se usará un valor con semilla para que repita los valores exactos (por ejemplo, para probar). Use Aleatorio sin semilla en su lugar.

2

¿Necesariamente necesita crear el new Random() dentro de su método random(int i)? Si está OBLIGADO a hacerlo de esa manera, podría usar, podría establecer la semilla a la hora actual, aunque eso no es a prueba de fallas, porque podría llamar a su numbers.random(10) tan rápido después de la otra que terminaría siendo el mismo semilla. Puede intentar tal vez usar nanoSeconds (System.nanoTime(), creo? Y si setSeed solo acepta int, multiplíquelo, supongo).

Lo que sugeriría sin embargo, si se le permite hacerlo, es declarar su Random fuera de su método. Si instancia su variable aleatoria en, por ejemplo, su constructor de clase number, puede establecer cualquier semilla y cada vez que llame a su método, le dará un nuevo número. (Serán los mismos conjuntos de números cada vez que reinicie su aplicación si usa una semilla constante; sin embargo, también podría usar el tiempo como semilla en este caso).

Finalmente, el último problema podría ser si declara varias clases number al mismo tiempo. Todos tendrán la misma semilla al azar y te darán el mismo conjunto de números aleatorios. Si esto sucede, puede hacer un static Random en su clase principal, y llamarlo en su clase de números. Sin embargo, esto unirá esas dos clases, pero funcionaría.Otra opción sería enviar un valor de incremento a su constructor de clase number, por cada number instancia, y usar el valor que pase como semilla.

La segunda opción debería ser buena para usted, si se le permite hacerlo de esa manera.

12

Hay dos problemas que causan lo que ves. El primero es que el código establece un valor inicial para una instancia Aleatoria. El segundo es que el método instancia "aleatorio" instancia un nuevo objeto aleatorio y luego establece inmediatamente su semilla con la misma semilla cada vez. La combinación de estas dos garantías de que, por el mismo valor de i, el método "aleatorio" siempre devolverá el mismo valor y siempre será el primero en la secuencia que la semilla siempre genera.

Asumiendo que la configuración de la semilla es obligatoria, para obtener el siguiente valor en la secuencia en lugar del mismo primer valor de la secuencia cada vez, la instancia randnum de Random no puede establecerse cada vez antes de su siguiente método se llama. Para solucionarlo, mueva la instancia de randnum local variable de Random desde el alcance del método de instancia aleatorio al ámbito de clase. En segundo lugar, establezca la semilla solo cuando se le asigne una instancia Aleatoria aleatoria o solo para obtener la misma secuencia de resultados para volver a comenzar. El método de instancia setSeed (semilla larga) de Class Random no se puede ejecutar en el alcance de la clase, por lo que el constructor tiene que establecerlo usando el constructor Random con el parámetro seed largo. El siguiente código muestra los cambios:

public class RandomDemo { // arbitrary example class name 
    // lots of class related stuff may be here... 

    // still inside the class scope... 
    // private is a good idea unless an external method needs to change it 
    private Random randnum = new Random(123456789L); 
    // the seed guarantees it will always produce the same sequence 
    // of pseudo-random values when the next methods get called 
    // for unpredicable sequences, use the following constructor instead: 
    // private Random randnum = new Random(); 

    // lots of code may be here... 

    // publicly exposed instance method for getting random number 
    // from a sequence determined by seed 123456789L 
    // in the range from 0 through i-1 
    public int randnum(int i) { 
     // don't set the seed in here, or randnum will return the exact same integer 
     // for the same value of i on every method call 
     // nextInt(i) will give the next value from randnum conforming to range i 
     return randnum.nextInt(i); 
    } // end randnum 

    // lots of more code may be here... 

} // end class RandDemo 

Lo anterior le dará una solución exacta a su problema exacto, como se indica. Sin embargo, usar una semilla obligatoria parece inusual, dado lo que hace.

Si esto es para un proyecto de clase o una prueba de software donde la secuencia tiene que ser predecible y repetible, tiene sentido establecer la semilla en un valor fijo. De lo contrario, cuestione la validez de establecer la semilla en algún valor predeterminado. A continuación, se explica más acerca de Random, semillas para Random y por qué hay una disposición para el suministro de una semilla.

Random tiene dos constructores:

Random() 

y

Random(long seed) 

y un método de instancia

setSeed(long seed) 

que todos afectan la secuencia de números obtenidos a partir de una instancia aleatoria. El método de instancia,

setSeed(long seed) 

establece el objeto aleatorio al mismo estado que habría sido en si se hubiera simplemente ejemplificada con la misma simiente como el argumento del constructor. Solo se utilizan los 48 bits de bajo orden de un valor inicial.

Si un objeto Random se instancia sin una semilla, la semilla será la misma que la hora del sistema en milisegundos. Esto garantiza que, a menos que se realicen instancias de dos objetos aleatorios en el mismo milisegundo, producirán diferentes secuencias pseudoaleatorias. Solo se usan los 48 bits de menor valor de la semilla. Esto causa secuencias pseudoaleatorias impredecibles. No es necesario y es un desperdicio de recursos de computación obtener una nueva instancia de Aleatorio cada vez que uno llama al siguiente método.

Los parámetros de inicialización de Random se proporcionan para que uno pueda instanciar un objeto aleatorio que produzca una secuencia repetible. Para una semilla dada, se garantiza que la secuencia de valores en los siguientes métodos será la misma secuencia siempre que se use esa semilla.Esto es útil para probar software que utilizará secuencias pseudoaleatorias donde los resultados deben ser predecibles y repetibles. No es útil para crear diferentes secuencias pseudoaleatorias impredecibles en funcionamiento.

La afirmación "es obligatorio que establezca la semilla" niega cualquier imprevisibilidad de las secuencias pseudoaleatorias del objeto Random. ¿Esto es para un proyecto de clase o prueba de software donde los resultados tienen que ser los mismos para las mismas entradas al programa?

Cuestiones relacionadas