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.


Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow