Szukaj…


Uwagi

Nic tak naprawdę nie jest przypadkowe, dlatego javadoc nazywa te liczby pseudolosami. Te liczby są tworzone za pomocą generatora liczb pseudolosowych .

Pseudolosowe liczby

Java stanowi, jako część pakietu utils , podstawowy generator liczb pseudolosowych o odpowiedniej nazwie Random . Tego obiektu można użyć do wygenerowania pseudolosowej wartości jako dowolnego z wbudowanych numerycznych typów danych ( int , float itp.). Możesz go również użyć do wygenerowania losowej wartości logicznej lub losowej tablicy bajtów. Przykład użycia jest następujący:

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.

UWAGA: Ta klasa produkuje tylko pseudolosowe liczby dość niskiej jakości i nigdy nie powinna być używana do generowania liczb losowych dla operacji kryptograficznych lub innych sytuacji, w których losowość o wyższej jakości jest krytyczna (w tym celu należy SecureRandom klasy SecureRandom , jak wspomniano poniżej). Wyjaśnienie rozróżnienia między „bezpieczną” i „niepewną” losowością wykracza poza zakres tego przykładu.

Pseudolosowe liczby w określonym zakresie

Metoda nextInt(int bound) Random przyjmuje górną granicę wyłączności, tj. Liczbę, której zwrócona losowa wartość musi być mniejsza niż. Jednak tylko metoda nextInt akceptuje powiązanie; nextLong , nextDouble itp. nie.

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

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

Począwszy od Java 1.7, możesz także używać ThreadLocalRandom ( źródło ). Ta klasa zapewnia bezpieczny wątek PRNG (generator liczb pseudolosowych). Zauważ, że metoda nextInt tej klasy akceptuje zarówno górną, jak i dolną granicę.

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);

Zauważ, że oficjalna dokumentacja stwierdza, że nextInt(int bound) może robić dziwne rzeczy, gdy bound jest blisko 2 30 +1 (wyróżnienie dodane):

Algorytm jest nieco trudny. Odrzuca wartości, które spowodowałyby nierównomierny rozkład (ze względu na fakt, że 2 ^ 31 nie jest podzielne przez n). Prawdopodobieństwo odrzucenia wartości zależy od n. Najgorszym przypadkiem jest n = 2 ^ 30 + 1, dla którego prawdopodobieństwo odrzucenia wynosi 1/2, a oczekiwana liczba iteracji przed zakończeniem pętli wynosi 2.

Innymi słowy, określenie wartości granicznej (nieznacznie) zmniejszy wydajność metody nextInt , a spadek wydajności stanie się bardziej wyraźny, gdy bound zbliży się do połowy maksymalnej wartości int.

Generowanie kryptograficznie bezpiecznych liczb pseudolosowych

Random i ThreadLocalRandom są wystarczająco dobre do codziennego użytku, ale mają duży problem: są oparte na liniowym generatorze kongruencjalnym , algorytmie, którego wynik można dość łatwo przewidzieć. Zatem te dwie klasy nie są odpowiednie do zastosowań kryptograficznych (takich jak generowanie kluczy).

Można użyć java.security.SecureRandom w sytuacjach, gdy wymagany jest PRNG z wyjściem, który jest bardzo trudny do przewidzenia. Przewidywanie liczb losowych utworzonych przez instancje tej klasy jest wystarczająco trudne, aby oznaczyć klasę jako bezpieczną kryptograficznie .

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));
    }
}

Oprócz bezpieczeństwa kryptograficznego SecureRandom ma gigantyczny okres 2 160 , w porównaniu z okresem 2 48 Random . Ma jednak jedną wadę: jest znacznie wolniejszy niż Random i inne liniowe PRNG, takie jak Mersenne Twister i Xorshift .

Należy pamiętać, że implementacja SecureRandom zależy zarówno od platformy, jak i dostawcy. Domyślny SecureRandom (podany przez dostawcę SUN w sun.security.provider.SecureRandom ):

  • w systemach uniksopodobnych, obsadzonych danymi z /dev/random i / lub /dev/urandom .
  • w systemie Windows zaszczepione wywołaniami CryptGenRandom() w CryptoAPI .

Wybierz losowe liczby bez duplikatów

/**
 * 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;
}

Metoda działa poprzez zapętlanie tablicy, która ma rozmiar żądanej długości i znajduje pozostałą długość możliwych liczb. Ustawia losową liczbę tych możliwych liczb newRandSpot i znajduje tę liczbę w obrębie niewykorzystanej liczby, która pozostała. Robi to, zapętlając zakres i sprawdzając, czy ta liczba została już zajęta.


Na przykład, jeśli zakres wynosi 5, a długość wynosi 3, a my już wybraliśmy liczbę 2. Następnie mamy 4 pozostałe liczby, więc otrzymujemy losową liczbę od 1 do 4 i zapętlamy zakres (5) pomijając dowolne liczby które już wykorzystaliśmy (2).

Powiedzmy teraz, że następną liczbą wybraną między 1 a 4 jest 3. W pierwszej pętli otrzymujemy 1, która nie została jeszcze zajęta, więc możemy usunąć 1 z 3, czyniąc ją 2. Teraz w drugiej pętli otrzymujemy 2, która została zajęta więc nic nie robimy. Podążamy za tym wzorem, aż dojdziemy do 4, gdzie po usunięciu 1 staje się 0, więc ustawiamy nowy randomNumber na 4.

Generowanie liczb losowych z określonym ziarnem

//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);

Użycie tego samego zarodka do generowania liczb losowych zwróci za każdym razem te same liczby, więc ustawienie innego zarodka dla każdej Random instancji jest dobrym pomysłem, jeśli nie chcesz skończyć z duplikatami liczb.

Dobrym sposobem, aby uzyskać Long , który jest inny dla każdego wywołania jest System.currentTimeMillis() :

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

Generowanie liczb losowych przy użyciu wspólnego apache lang3

Możemy użyć org.apache.commons.lang3.RandomUtils do generowania liczb losowych za pomocą pojedynczej linii.

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

Metoda nextInt(int startInclusive, int endExclusive) ma zakres.

Oprócz int, możemy generować losowe long , double , float i bytes za pomocą tej klasy.

Klasa RandomUtils zawiera następujące metody:

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
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow