Ricerca…


Osservazioni

Niente è veramente casuale e quindi javadoc chiama quei numeri pseudocasuali. Questi numeri sono creati con un generatore di numeri pseudocasuali .

Pseudo numeri casuali

Java fornisce, come parte del pacchetto utils , un generatore di numeri pseudo-casuali di base, opportunamente chiamato Random . Questo oggetto può essere utilizzato per generare un valore pseudo-casuale come qualsiasi dei tipi di dati numerici incorporati ( int , float , ecc.). Puoi anche usarlo per generare un valore booleano casuale o una matrice casuale di byte. Un esempio di utilizzo è il seguente:

import java.util.Random;  

...
  
Random random = new Random();
int randInt = random.nextInt();
long randLong = random.nextLong();

double randDouble = random.nextDouble(); //This returns a value between 0.0 and 1.0
float randFloat = random.nextFloat(); //Same as nextDouble

byte[] randBytes = new byte[16];
random.nextBytes(randBytes); //nextBytes takes a user-supplied byte array, and fills it with random bytes. It returns nothing.

NOTA: questa classe produce solo numeri pseudo-casuali di bassa qualità e non dovrebbe mai essere utilizzata per generare numeri casuali per operazioni crittografiche o altre situazioni in cui la casualità di qualità superiore è fondamentale (per questo, si vorrebbe usare la classe SecureRandom , come indicato di seguito). Una spiegazione della distinzione tra casualità "sicura" e "insicura" esula dallo scopo di questo esempio.

Numeri casuali falsi in un intervallo specifico

Il metodo nextInt(int bound) di Random accetta un limite esclusivo superiore, ovvero un numero che il valore casuale restituito deve essere inferiore a. Tuttavia, solo il metodo nextInt accetta un limite; nextLong , nextDouble ecc. no.

Random random = new Random();
random.nextInt(1000); // 0 - 999

int number = 10 + random.nextInt(100); // number is in the range of 10 to 109

A partire da Java 1.7, puoi anche usare ThreadLocalRandom ( source ). Questa classe fornisce un PRNG sicuro per thread (generatore di numeri pseudo-casuali). Si noti che il metodo nextInt di questa classe accetta sia un limite superiore che uno inferiore.

import java.util.concurrent.ThreadLocalRandom;

// nextInt is normally exclusive of the top value,
// so add 1 to make it inclusive
ThreadLocalRandom.current().nextInt(min, max + 1);

Si noti che la documentazione ufficiale afferma che nextInt(int bound) può fare cose strane quando bound è vicino a 2 30 +1 (enfasi aggiunta):

L'algoritmo è leggermente complicato. Respinge i valori che risulterebbero in una distribuzione non uniforme (a causa del fatto che 2 ^ 31 non è divisibile per n). La probabilità che un valore venga rifiutato dipende da n. Il caso peggiore è n = 2 ^ 30 + 1, per cui la probabilità di uno scarto è 1/2, e il numero previsto di iterazioni prima che il ciclo termini è 2.

In altre parole, la specificazione di un limite diminuirà (leggermente) le prestazioni del metodo nextInt e questa riduzione delle prestazioni diventerà più pronunciata quando il bound avvicina a metà del valore massimo int.

Generazione di numeri pseudocasuali crittograficamente sicuri

Random e ThreadLocalRandom sono abbastanza buoni per l'uso quotidiano, ma hanno un grosso problema: si basano su un generatore congruenziale lineare , un algoritmo il cui output può essere predetto piuttosto facilmente. Pertanto, queste due classi non sono adatte per usi crittografici (come la generazione di chiavi).

È possibile utilizzare java.security.SecureRandom in situazioni in cui è richiesto un PRNG con un output molto difficile da prevedere. Prevedere i numeri casuali creati dalle istanze di questa classe è abbastanza difficile da etichettare la classe come crittograficamente sicura .

import java.security.SecureRandom;
import java.util.Arrays;

public class Foo {
    public static void main(String[] args) {
        SecureRandom rng = new SecureRandom();
        byte[] randomBytes = new byte[64];
        rng.nextBytes(randomBytes); // Fills randomBytes with random bytes (duh)
        System.out.println(Arrays.toString(randomBytes));
    }
}

Oltre a essere crittograficamente sicuro, SecureRandom ha un periodo gigantesco di 2 160 , rispetto al periodo di Random di 2 48 . Ha uno svantaggio di essere considerevolmente più lento di Random e altri PRNG lineari come Mersenne Twister e Xorshift , comunque.

Si noti che l'implementazione SecureRandom è dipendente dalla piattaforma e dal fornitore. Il SecureRandom predefinito (fornito dal provider SUN in sun.security.provider.SecureRandom ):

  • su sistemi simil-Unix, seminato con dati da /dev/random e / o /dev/urandom .
  • su Windows, seminato con chiamate a CryptGenRandom() in CryptoAPI .

Seleziona numeri casuali senza duplicati

/**
 * returns a array of random numbers with no duplicates
 * @param range the range of possible numbers for ex. if 100 then it can be anywhere from 1-100
 * @param length the length of the array of random numbers
 * @return array of random numbers with no duplicates.
 */
public static int[] getRandomNumbersWithNoDuplicates(int range, int length){
    if (length<range){
        // this is where all the random numbers
        int[] randomNumbers = new int[length];
        
        // loop through all the random numbers to set them
        for (int q = 0; q < randomNumbers.length; q++){
            
            // get the remaining possible numbers
            int remainingNumbers = range-q;
            
            // get a new random number from the remainingNumbers
            int newRandSpot = (int) (Math.random()*remainingNumbers);
            
            newRandSpot++;
            
            // loop through all the possible numbers
            for (int t = 1; t < range+1; t++){
                
                // check to see if this number has already been taken
                boolean taken = false;
                for (int number : randomNumbers){
                    if (t==number){
                        taken = true;
                        break;
                    }
                }
                
                // if it hasnt been taken then remove one from the spots
                if (!taken){
                    newRandSpot--;
                    
                    // if we have gone though all the spots then set the value
                    if (newRandSpot==0){
                        randomNumbers[q] = t;
                    }
                }
            }
        }
        return randomNumbers;
    } else {
        // invalid can't have a length larger then the range of possible numbers
    }
    return null;
}

Il metodo funziona eseguendo il ciclo su un array che ha le dimensioni della lunghezza richiesta e trova la lunghezza rimanente dei numeri possibili. Imposta un numero casuale di quei possibili numeri newRandSpot e trova quel numero all'interno del numero non occupato rimasto. Lo fa scorrendo l'intervallo e controllando per vedere se quel numero è già stato preso.


Ad esempio se l'intervallo è 5 e la lunghezza è 3 e abbiamo già scelto il numero 2. Quindi abbiamo 4 numeri rimanenti in modo da ottenere un numero casuale compreso tra 1 e 4 e passiamo attraverso l'intervallo (5) saltando sopra qualsiasi numero che abbiamo già usato (2).

Ora diciamo che il prossimo numero scelto tra 1 e 4 è 3. Nel primo ciclo otteniamo 1 che non è ancora stato preso così possiamo rimuovere 1 da 3 e renderlo 2. Ora sul secondo ciclo otteniamo 2 che è stato preso quindi non facciamo niente Seguiamo questo modello finché non arriviamo a 4, dove una volta rimosso 1 diventa 0, quindi impostiamo il nuovo numero casuale su 4.

Generazione di numeri casuali con un seme specificato

//Creates a Random instance with a seed of 12345.
Random random = new Random(12345L);

//Gets a ThreadLocalRandom instance
ThreadLocalRandom tlr = ThreadLocalRandom.current();

//Set the instance's seed.
tlr.setSeed(12345L);

Usare lo stesso seme per generare numeri casuali restituirà sempre gli stessi numeri, quindi impostare un seme diverso per ogni istanza Random è una buona idea se non vuoi finire con numeri duplicati.

Un buon metodo per ottenere un Long diverso da ogni chiamata è System.currentTimeMillis() :

Random random = new Random(System.currentTimeMillis());
ThreadLocalRandom.current().setSeed(System.currentTimeMillis());

Generazione di numeri casuali usando lang3 apache-common

Possiamo usare org.apache.commons.lang3.RandomUtils per generare numeri casuali usando una singola riga.

int x = RandomUtils.nextInt(1, 1000);

Il metodo nextInt(int startInclusive, int endExclusive) accetta un intervallo.

Oltre a int, possiamo generare long , double , float e bytes casuali usando questa classe.

RandomUtils classe RandomUtils contiene i seguenti metodi:

static byte[] nextBytes(int count) //Creates an array of random bytes.
static double nextDouble() //Returns a random double within 0 - Double.MAX_VALUE
static double nextDouble(double startInclusive, double endInclusive) //Returns a random double within the specified range.
static float nextFloat() //Returns a random float within 0 - Float.MAX_VALUE
static float nextFloat(float startInclusive, float endInclusive) //Returns a random float within the specified range.
static int nextInt() //Returns a random int within 0 - Integer.MAX_VALUE
static int nextInt(int startInclusive, int endExclusive) //Returns a random integer within the specified range.
static long nextLong() //Returns a random long within 0 - Long.MAX_VALUE
static long nextLong(long startInclusive, long endExclusive) //Returns a random long within the specified range.


Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow