Zoeken…


Opmerkingen

Niets is echt willekeurig en dus noemt de javadoc die nummers pseudo-willekeurig. Die nummers worden gemaakt met een pseudorandom-nummergenerator .

Pseudo willekeurige nummers

Java biedt, als onderdeel van het utils pakket, een eenvoudige pseudo-willekeurige nummergenerator, toepasselijk genaamd Random . Dit object kan worden gebruikt om een pseudo-willekeurige waarde te genereren als een van de ingebouwde numerieke gegevenstypen ( int , float , enz.). U kunt het ook gebruiken om een willekeurige Booleaanse waarde of een willekeurige reeks bytes te genereren. Een voorbeeldgebruik is als volgt:

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.

OPMERKING: deze klasse produceert alleen pseudo-willekeurige getallen van redelijk lage kwaliteit en mag nooit worden gebruikt om willekeurige getallen te genereren voor cryptografische bewerkingen of andere situaties waarin een hogere kwaliteit van cruciaal belang is (daarvoor zou u de SecureRandom klasse willen gebruiken, zoals hieronder vermeld). Een verklaring voor het onderscheid tussen "veilige" en "onzekere" willekeurigheid valt buiten het bestek van dit voorbeeld.

Pseudo-willekeurige getallen in specifiek bereik

De methode nextInt(int bound) van Random accepteert een bovenste exclusieve grens, dat wil zeggen een getal dat de geretourneerde willekeurige waarde kleiner moet zijn dan. Alleen de methode nextInt accepteert echter een bound; nextLong , nextDouble etc. niet.

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

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

Vanaf Java 1.7 kunt u ook ThreadLocalRandom ( bron ) gebruiken. Deze klasse biedt een thread-safe PRNG (pseudo-random number generator). Merk op dat de nextInt methode van deze klasse zowel een boven- als een ondergrens accepteert.

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

Merk op dat de officiële documentatie stelt dat nextInt(int bound) rare dingen kan doen wanneer bound bijna 2 30 +1 is (nadruk toegevoegd):

Het algoritme is enigszins lastig. Het verwerpt waarden die zouden resulteren in een ongelijke verdeling (vanwege het feit dat 2 ^ 31 niet deelbaar is door n). De kans dat een waarde wordt afgewezen, is afhankelijk van n. Het slechtste geval is n = 2 ^ 30 + 1, waarvoor de kans op een afwijzing 1/2 is, en het verwachte aantal iteraties voordat de lus eindigt, is 2.

Met andere woorden, het specificeren van een bound zal (enigszins) de prestaties van de nextInt methode verminderen, en deze prestatievermindering zal meer uitgesproken worden naarmate de bound de helft van de maximale int-waarde nadert.

Cryptografisch beveiligde pseudo-willekeurige getallen genereren

Random en ThreadLocalRandom zijn goed genoeg voor dagelijks gebruik, maar ze hebben een groot probleem: ze zijn gebaseerd op een lineaire congruentiële generator , een algoritme waarvan de output vrij eenvoudig kan worden voorspeld. Deze twee klassen zijn dus niet geschikt voor cryptografisch gebruik (zoals het genereren van sleutels).

Men kan java.security.SecureRandom in situaties waarin een PRNG met een uitvoer die moeilijk te voorspellen is vereist is. Het voorspellen van de willekeurige getallen die door instanties van deze klasse zijn gemaakt, is moeilijk genoeg om de klasse als cryptografisch veilig te labelen.

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 is niet alleen cryptografisch veilig, SecureRandom heeft ook een gigantische periode van 2 160 , vergeleken met Random s periode van 2 48 . Het heeft echter het nadeel dat het aanzienlijk langzamer is dan Random en andere lineaire PRNG's zoals Mersenne Twister en Xorshift .

Merk op dat de implementatie van SecureRandom zowel platform- als provider-afhankelijk is. De standaard SecureRandom (gegeven door de SUN provider in sun.security.provider.SecureRandom ):

  • op Unix-achtige systemen, bezaaid met gegevens van /dev/random en / of /dev/urandom .
  • op Windows, gezaaid met aanroepen naar CryptGenRandom() in CryptoAPI .

Selecteer willekeurige getallen zonder duplicaten

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

De methode werkt door een array door te lussen met de grootte van de gevraagde lengte en de resterende lengte van mogelijke getallen vindt. Het stelt een willekeurig aantal van die mogelijke nummers newRandSpot en vindt dat nummer binnen het resterende niet-genomen nummer. Het doet dit door het bereik te doorlopen en te controleren of dat nummer al in gebruik is.


Als het bereik bijvoorbeeld 5 is en de lengte 3 is en we het nummer 2 al hebben gekozen, hebben we 4 resterende nummers, dus krijgen we een willekeurig getal tussen 1 en 4 en lopen we door het bereik (5) en slaan we alle nummers over die we al hebben gebruikt (2).

Laten we nu zeggen dat het volgende nummer gekozen tussen 1 en 4 3 is. In de eerste lus krijgen we 1 die nog niet is genomen, dus we kunnen 1 verwijderen uit 3 waardoor het 2 wordt. Nu in de tweede lus krijgen we 2 die is genomen dus we doen niets. We volgen dit patroon tot we bij 4 komen, zodra we 1 verwijderen, wordt het 0, dus stellen we het nieuwe randomNumber in op 4.

Willekeurige getallen genereren met een opgegeven seed

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

Als u dezelfde seed gebruikt om willekeurige getallen te genereren, retourneert u elke keer dezelfde getallen, dus het instellen van een andere seed voor elke Random instantie is een goed idee als u niet met dubbele getallen wilt eindigen.

Een goede methode om een Long te krijgen die voor elke oproep anders is, is System.currentTimeMillis() :

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

Willekeurig nummer genereren met behulp van apache-common lang3

We kunnen org.apache.commons.lang3.RandomUtils gebruiken om willekeurige getallen met een enkele regel te genereren.

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

De methode nextInt(int startInclusive, int endExclusive) heeft een bereik.

Naast int kunnen we met deze klasse willekeurige long , double , float en bytes genereren.

RandomUtils klasse RandomUtils bevat de volgende 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
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow