Java random restituisce sempre lo stesso numero quando imposto il seed?

Ho bisogno di aiuto con un generatore di numeri casuali che sto creando. Il mio codice è il seguente (all’interno di una class chiamata numeri):

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

Quando chiamo questo metodo da un’altra class (per generare un numero casuale), restituisce sempre lo stesso numero. Per esempio se dovessi fare:

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

stampa sempre lo stesso numero es. 5 5. Cosa devo fare per stampare due numeri diversi, ad es. 5 8

È obbligatorio che io abbia impostato il seme.

Grazie

Devi condividere l’istanza Random() sull’intera class:

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

Se imposti sempre il seme, otterrai sempre la stessa risposta. Questo è ciò che fa il seme.

Ci sono due problemi che causano ciò che vedi. Il primo è che il codice imposta un valore di inizializzazione per un’istanza Random. Il secondo è che il metodo di istanza “casuale” istanze un nuovo object casuale e quindi imposta immediatamente il seme con lo stesso seme ogni volta. La combinazione di questi due garantisce che, per lo stesso valore di i, il metodo “random” restituirà sempre lo stesso valore e sarà sempre il primo nella sequenza che il seme genera sempre.

Supponendo che l’impostazione del seed sia obbligatoria, per ottenere il valore successivo nella sequenza anziché lo stesso primo valore della sequenza ogni volta, l’istanza randn di Random non può avere il suo seed set ogni volta prima che venga chiamato il suo prossimo metodo. Per risolvere ciò, spostare l’istanza della variabile locale rand di Random dall’ambito del metodo di istanza casuale all’ambito della class. In secondo luogo, imposta il seme solo quando a caso viene assegnata un’istanza casuale o solo per ottenere la stessa sequenza di risultati da esso per ricominciare da capo. Il metodo di istanza setSeed (long seed) di Class Random non può essere eseguito nell’ambito della class, quindi il costruttore deve impostarlo utilizzando il costruttore Random con il parametro long seed. Il codice seguente mostra le modifiche:

 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 

Quanto sopra ti darà una soluzione esatta al tuo problema esatto, come affermato. Tuttavia, usare un seme obbligatorio sembra inusuale, dato quello che fa.

Se si tratta di un progetto di class o di un test del software in cui la sequenza deve essere prevedibile e ripetibile, è opportuno impostare il seme su un valore fisso. Altrimenti, mettere in discussione la validità di impostare il seme su un valore predeterminato. Quanto segue spiega di più su Random, seed per Random e perché esiste una disposizione per fornire un seed.

Casuale ha due costruttori:

 Random() 

e

 Random(long seed) 

e un metodo di istanza

 setSeed(long seed) 

che tutti influenzano la sequenza di numeri ottenuti da un’istanza Random. Il metodo di istanza,

 setSeed(long seed) 

imposta l’object Random sullo stesso stato in cui sarebbe stato se fosse stato appena istanziato con lo stesso seme dell’argomento del costruttore. Vengono utilizzati solo i 48 bit di basso livello di un valore di inizializzazione.

Se un object casuale viene istanziato senza un seme, il seme sarà uguale al tempo di sistema in millisecondi. Ciò garantisce che, a meno di due istanti randomizzati nello stesso millisecondo, generino sequenze pseudo-casuali diverse. Vengono utilizzati solo i 48 bit di ordine basso del valore di inizializzazione. Ciò causa sequenze pseudo-casuali imprevedibili. Non è necessario e sprecato risorse di calcolo per ottenere una nuova istanza di Random ogni volta che si chiama un metodo successivo.

I parametri seme di Random sono forniti in modo tale che si possa istanziare un object casuale che produce una sequenza ripetibile. Per un dato seme, la sequenza di valori nei metodi successivi è garantita per essere la stessa sequenza ogni volta che viene utilizzato quel seme. Questo è utile per testare il software che utilizzerà sequenze pseudo-casuali in cui i risultati devono essere prevedibili e ripetibili. Non è utile per creare sequenze pseudo-casuali imprevedibili durante il funzionamento.

L’affermazione “è obbligatorio impostare il seme” annulla qualsiasi imprevedibilità delle sequenze pseudo-casuali dell’object Random. È questo per un progetto di class o un test del software in cui i risultati devono essere gli stessi per gli stessi ingressi al programma?

Imposta il seme una volta all’avvio, anziché ogni volta che vuoi un nuovo numero casuale.

Quello che stai usando non è un generatore di numeri casuali, è un generatore di numeri pseudo-casuali. Il PRNG genera sequenze di numeri pseudo-casuali, il seme seleziona un punto di partenza in una sequenza (un PRNG può generare una o più sequenze).

Devi necessariamente creare il new Random() all’interno del tuo metodo random(int i) ? Se sei OBBLIGATO a farlo in quel modo, potresti usare, potresti impostare il seme all’ora corrente, anche se questo non è un fallimento, perché potresti chiamare il tuo numbers.random(10) così velocemente dopo l’altro che sarebbe finiscono per essere lo stesso seme. Potresti provare a utilizzare nanoSeconds (System.nanoTime () penso? E se setSeed accetta solo int, moltiplica, suppongo).

Quello che suggerirei comunque, se ti è permesso farlo, è dichiarare il tuo casuale al di fuori del tuo metodo. Se instanziate la vostra variabile casuale in, per esempio, il vostro costruttore di classi number , potete impostare qualsiasi seme e ogni volta che chiamate il vostro metodo, vi darebbe un nuovo numero. (Saranno gli stessi gruppi di numeri ogni volta che riavvierai la tua applicazione se usi un seme costante comunque, potresti usare anche il tempo come seme in questo caso).

Infine, l’ultimo problema potrebbe essere se si dichiarano diverse classi di number contemporaneamente. Avranno tutti lo stesso seme casuale e ti daranno lo stesso numero di numeri casuali. Se ciò accade, puoi creare un static Random nella tua class principale e chiamarlo nella class dei numeri. Questo accoppierà queste due classi, ma funzionerebbe. Un’altra opzione potrebbe essere quella di inviare un valore incrementale al costruttore della class number , per ogni number che instanziate, e utilizzare il valore che si passa come seme.

La seconda opzione dovrebbe essere buona per te, se ti è permesso farlo in quel modo.

Di solito, Random non è veramente casuale ma è pseudocasuale. Significa che prende un dato seme e lo usa per generare una sequenza di numeri che sembra casuale (ma è prevedibilmente prevedibile e si ripete se si mette lo stesso seme).

Se non si mette seme, il primo seme sarà preso da una fonte variabile (solitamente l’ora del sistema).

Di solito, verrà utilizzato un valore con seed per fare in modo che ripeta i valori esatti (ad esempio, per il test). Usa invece casuale senza seme.