Java Language
Generowanie liczb losowych
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.