Sök…


Anmärkningar

Ingenting är verkligen slumpmässigt och därför kallar javadoc dessa nummer pseudorandom. Dessa nummer skapas med en pseudorandom-nummergenerator .

Pseudo slumpmässiga siffror

Java tillhandahåller, som en del av utils , en grundläggande pseudo-slumpmässig talgenerator, lämpligt benämnd Random . Detta objekt kan användas för att generera ett pseudo-slumpmässigt värde som någon av de inbyggda numeriska datatyperna ( int , float , etc). Du kan också använda den för att generera ett slumpmässigt booleskt värde eller en slumpmässig matris. Exempel på användning är följande:

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.

OBS: Denna klass producerar bara ganska lågkvalitativa pseudo-slumpmässiga nummer och bör aldrig användas för att generera slumpmässiga nummer för kryptografiska operationer eller andra situationer där slumpmässighet av högre kvalitet är kritisk (för det vill du använda klassen SecureRandom , som anges nedan). En förklaring till skillnaden mellan "säker" och "osäker" slumpmässighet ligger utanför detta exempel.

Pseudo slumpmässiga nummer inom ett specifikt intervall

Metoden nextInt(int bound) för Random accepterar en övre exklusiva gräns, dvs ett tal som det returnerade slumpmässiga värdet måste vara mindre än. Men bara the nextInt metoden accepterar en bunden; nextLong , nextDouble etc. gör det inte.

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

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

Från och med Java 1.7 kan du också använda ThreadLocalRandom ( källa ). Denna klass tillhandahåller en gängsäker PRNG (pseudo-random number generator). Observera att metoden nextInt i denna klass accepterar både en övre och nedre gräns.

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

Observera att den officiella dokumentationen anger att nextInt(int bound) kan göra konstiga saker när bound är nära 2 30 +1 (betoning tillagd):

Algoritmen är lite knepig. Den avvisar värden som skulle resultera i en ojämn fördelning (på grund av att 2 ^ 31 inte kan delas med n). Sannolikheten för att ett värde avvisas beror på n. Det värsta fallet är n = 2 ^ 30 + 1, varvid sannolikheten för ett avslag är 1/2, och det förväntade antalet iterationer innan slingan upphör är 2.

Med andra ord, att specificera en bunden kommer (något) att minska prestandan för nextInt metoden, och denna prestationsminskning kommer att bli mer uttalad när bound närmar sig halva det maximala int-värdet.

Genererar kryptografiskt säkra pseudorandomnummer

Random och ThreadLocalRandom är tillräckligt bra för vardagligt bruk, men de har ett stort problem: De är baserade på en linjär kongruentialgenerator , en algoritm vars output kan förutsägas ganska enkelt. Således är dessa två klasser inte lämpliga för kryptografisk användning (till exempel nyckelgenerering).

Man kan använda java.security.SecureRandom i situationer där en PRNG med en utgång som är mycket svår att förutsäga krävs. Att förutsäga slumpmässiga siffror som skapats av instanser av denna klass är tillräckligt svårt för att beteckna klassen som kryptografiskt säker .

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

Förutom att vara kryptografiskt säkert har SecureRandom en gigantisk period på 2 160 jämfört med Random perioden på 2 48 . Det har en nackdel med att vara betydligt långsammare än Random och andra linjära PRNG: er som Mersenne Twister och Xorshift , dock.

Observera att SecureRandom-implementering är både plattforms- och leverantörsberoende. Standard SecureRandom (ges av SUN leverantören i sun.security.provider.SecureRandom ):

  • på Unix-liknande system, utsäde med data från /dev/random och / eller /dev/urandom .
  • på Windows, med CryptGenRandom() till CryptGenRandom() i CryptoAPI .

Välj slumpmässiga nummer utan dubbletter

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

Metoden fungerar genom att slinga genom en matris som har storleken på den begärda längden och hittar återstående längd på möjliga nummer. Den ställer ett slumpmässigt antal av dessa möjliga nummer newRandSpot och hittar det numret inom det icke tagna numret kvar. Det gör detta genom att slinga genom intervallet och kontrollera om det numret redan har tagits.


Till exempel om intervallet är 5 och längden är 3 och vi redan har valt siffran 2. Sedan har vi 4 återstående siffror så vi får ett slumpmässigt nummer mellan 1 och 4 och vi går genom intervallet (5) som hoppar över alla siffror som vi redan har använt (2).

Låt oss nu säga att nästa nummer valt mellan 1 och 4 är 3. På den första slingan får vi 1 som ännu inte har tagits så vi kan ta bort 1 från 3 vilket gör det till 2. Nu på den andra slingan får vi 2 som har tagits så vi gör ingenting. Vi följer detta mönster tills vi kommer till 4 där när vi tar bort 1 blir det 0 så vi sätter det nya randomNumber till 4.

Generera slumpmässiga nummer med ett specificerat frö

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

Att använda samma frö för att generera slumpmässiga nummer kommer att returnera samma nummer varje gång, så att ange ett annat frö för varje Random exempel är en bra idé om du inte vill sluta med duplicerade nummer.

En bra metod för att få en Long som skiljer sig åt varje samtal är System.currentTimeMillis() :

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

Genererar slumpmässigt nummer med apache-common lang3

Vi kan använda org.apache.commons.lang3.RandomUtils att generera slumpmässiga nummer med en enda rad.

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

Metoden nextInt(int startInclusive, int endExclusive) tar ett intervall.

Förutom int kan vi generera slumpmässiga long , double , float och bytes med denna klass.

RandomUtils klassen innehåller följande metoder-

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
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow