Java Language
Zufallszahlengenerierung
Suche…
Bemerkungen
Nichts ist wirklich zufällig und daher nennt der Javadoc diese Zahlen pseudozufällig. Diese Nummern werden mit einem Pseudozufallszahlengenerator erstellt .
Pseudo-Zufallszahlen
Java bietet als Teil des utils
Pakets einen grundlegenden Pseudo-Zufallszahlengenerator, der entsprechend als Random
. Dieses Objekt kann verwendet werden, um einen Pseudozufallswert als einen der eingebauten numerischen Datentypen ( int
, float
usw.) zu generieren. Sie können es auch verwenden, um einen zufälligen booleschen Wert oder ein zufälliges Byte-Array zu generieren. Ein Beispiel ist wie folgt:
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.
HINWEIS: Diese Klasse produziert nur ziemlich minderwertige Pseudozufallszahlen, und sollte nie Zufallszahlen für Verschlüsselungsoperationen oder andere Situationen , in denen hochwertigere Zufälligkeit kritisch zu erzeugen , verwendet werden (für das, würden Sie wollen , die verwenden SecureRandom
Klasse, wie unten angegeben). Eine Erklärung für die Unterscheidung zwischen "sicherer" und "unsicherer" Zufälligkeit liegt außerhalb des Rahmens dieses Beispiels.
Pseudo-Zufallszahlen in einem bestimmten Bereich
Die Methode nextInt(int bound)
von Random
akzeptiert eine obere Exklusivgrenze, dh eine Zahl, deren zurückgegebener Zufallswert kleiner sein muss. Allerdings akzeptiert nur die nextInt
Methode eine Bindung. nextLong
, nextDouble
usw. nicht.
Random random = new Random();
random.nextInt(1000); // 0 - 999
int number = 10 + random.nextInt(100); // number is in the range of 10 to 109
Ab Java 1.7 können Sie auch ThreadLocalRandom
( source ) verwenden. Diese Klasse stellt ein threadsicheres PRNG (Pseudo-Random Number Generator) bereit. Beachten Sie, dass die nextInt
Methode dieser Klasse sowohl eine obere als auch eine untere Grenze akzeptiert.
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);
Beachten Sie, dass die offizielle Dokumentation besagt, dass nextInt(int bound)
seltsame Dinge nextInt(int bound)
kann, wenn die bound
in der Nähe von 2 30 +1 liegt (Hervorhebung hinzugefügt):
Der Algorithmus ist etwas schwierig. Werte, die zu einer ungleichmäßigen Verteilung führen würden, werden zurückgewiesen (da 2 ^ 31 nicht durch n teilbar ist). Die Wahrscheinlichkeit, dass ein Wert abgelehnt wird, hängt von n ab. Der ungünstigste Fall ist n = 2 ^ 30 + 1, für den die Wahrscheinlichkeit einer Zurückweisung 1/2 ist und die erwartete Anzahl von Iterationen vor Abschluß der Schleife 2 beträgt.
nextInt
eine Grenze nextInt
, wird die Leistung der nextInt
Methode (geringfügig) verringert, und diese Leistungsabnahme wird deutlicher, wenn sich die bound
dem halben max int-Wert nähert.
Generierung kryptographisch sicherer Pseudozufallszahlen
Random
und ThreadLocalRandom
sind gut genug für den täglichen Gebrauch, sie haben jedoch ein großes Problem: Sie basieren auf einem linearen Kongruenzgenerator , einem Algorithmus, dessen Ausgabe ziemlich leicht vorhergesagt werden kann. Daher sind diese beiden Klassen nicht für kryptographische Zwecke (z. B. zur Schlüsselgenerierung) geeignet.
java.security.SecureRandom
in Situationen verwendet java.security.SecureRandom
in denen ein PRNG mit einer Ausgabe erforderlich ist, die sehr schwer vorherzusagen ist. Das Vorhersagen der Zufallszahlen, die durch Instanzen dieser Klasse erstellt werden, ist schwer genug, um die Klasse als kryptografisch sicher zu kennzeichnen .
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));
}
}
SecureRandom
ist nicht nur kryptografisch sicher, SecureRandom
verfügt auch über eine gigantische Periode von 2 160 im Vergleich zu Random
s von 2 48 . Sie hat jedoch den Nachteil, dass sie wesentlich langsamer ist als Random
und andere lineare PRNGs wie Mersenne Twister und Xorshift .
Beachten Sie, dass die SecureRandom-Implementierung sowohl plattform- als auch anbieterabhängig ist. Der SecureRandom
(gegeben durch SUN
- Anbieter in sun.security.provider.SecureRandom
):
- auf Unix-ähnlichen Systemen mit Daten aus
/dev/random
und / oder/dev/urandom
. - unter Windows mit Aufrufe an
CryptGenRandom()
in CryptoAPI .
Wählen Sie Zufallszahlen ohne Duplikate
/**
* 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;
}
Die Methode arbeitet, indem ein Array durchlaufen wird, das die angeforderte Länge hat und die verbleibende Länge möglicher Zahlen ermittelt. Es legt eine zufällige Anzahl dieser möglichen Zahlen newRandSpot
und ermittelt diese Zahl innerhalb der nicht newRandSpot
Anzahl. Dies geschieht durch Durchlaufen des Bereichs und Überprüfen, ob diese Nummer bereits vergeben ist.
Zum Beispiel, wenn der Bereich 5 ist und die Länge 3 ist und wir bereits die Zahl 2 gewählt haben. Dann haben wir 4 verbleibende Zahlen, so dass wir eine Zufallszahl zwischen 1 und 4 erhalten und wir durchlaufen den Bereich (5) und überspringen alle Zahlen das wir bereits verwendet haben (2).
Nehmen wir an, die nächste Zahl zwischen 1 und 4 ist 3. Die erste Schleife ergibt 1, die noch nicht genommen wurde, so dass wir 1 von 3 entfernen können, um 2 zu werden. Jetzt in der zweiten Schleife bekommen wir 2, die genommen wurde also machen wir nichts. Wir folgen diesem Muster, bis wir zu 4 gelangen, wenn wir 1 entfernen, wird es 0, und wir setzen die neue randomNumber auf 4.
Zufallszahlen mit einem angegebenen Startwert erzeugen
//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);
Wenn Sie den gleichen Startwert für die Generierung von Zufallszahlen verwenden, werden jedes Mal dieselben Zahlen zurückgegeben. Wenn Sie also für jede Random
einen anderen Startwert Random
empfiehlt es sich, wenn Sie nicht mit doppelten Zahlen enden möchten.
Eine gute Methode, um einen Long
, der bei jedem Aufruf anders ist, ist System.currentTimeMillis()
:
Random random = new Random(System.currentTimeMillis());
ThreadLocalRandom.current().setSeed(System.currentTimeMillis());
Zufallszahlen mit apache-common lang3 generieren
Wir können org.apache.commons.lang3.RandomUtils
, um Zufallszahlen mithilfe einer einzelnen Zeile zu generieren.
int x = RandomUtils.nextInt(1, 1000);
Die Methode nextInt(int startInclusive, int endExclusive)
nimmt einen Bereich an.
Abgesehen von int können wir mit dieser Klasse zufällige long
, double
, float
und bytes
generieren.
RandomUtils
Klasse enthält die folgenden Methoden:
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.