수색…


비고

아무것도 실제로 무작위가 아니기 때문에 javadoc은 그 숫자를 의사 난수라고 부릅니다. 이러한 숫자는 의사 난수 생성기를 사용하여 만듭니다.

가짜 난수

Java는 utils 패키지의 일부로 Random 이라는 이름의 기본 의사 난수 생성기를 제공합니다. 이 객체는 임의의 내장 숫자 데이터 유형 ( int , float 등)으로 의사 임의 값을 생성하는 데 사용할 수 있습니다. 또한이를 사용하여 임의의 부울 값 또는 임의의 바이트 배열을 생성 할 수 있습니다. 사용 예는 다음과 같습니다.

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.

참고 :이 클래스는 상당히 낮은 품질의 의사 난수를 생성하기 때문에 암호 연산이나 높은 품질의 임의성이 중요한 기타 상황에서 임의의 숫자를 생성하는 데 사용해서는 안됩니다 ( SecureRandom 클래스를 사용하려는 경우, 아래에서 언급했듯이). "안전"과 "안전하지 않은"임의성의 구분에 대한 설명은이 예제의 범위를 벗어납니다.

특정 범위의 의사 난수

Random 의 메소드 nextInt(int bound) 는 상위 배타적 경계, 즉 반환 된 임의 값이보다 작은 숫자 여야합니다. 다만, nextInt 메소드 만이 바인딩을 받아들입니다. nextLong , nextDouble 등은하지 않습니다.

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

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

Java 1.7부터는 ThreadLocalRandom ( source )을 사용할 수도 있습니다. 이 클래스는 thread 세이프 인 PRNG (의사 난수 생성 프로그램)를 제공합니다. 이 클래스의 nextInt 메소드는 상한과 하한을 모두 받아들입니다.

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

공식 문서 에서는 bound 가 2 30 +1 (강조가 추가됨) 근처에있을 때 nextInt(int bound) 가 이상한 것을 할 수 있다고 명시합니다.

알고리즘은 약간 까다 롭습니다. (2 ^ 31이 n으로 나눌 수 없다는 사실 때문에) 불균등 한 분포를 초래할 수있는 값을 거부합니다 . 값이 거부되는 확률은 n에 달려 있습니다. 최악의 경우는 n = 2 ^ 30 + 1이며,이 경우 거부의 확률은 1/2이고 루프가 끝나기 전에 예상되는 반복 횟수는 2입니다.

즉, 경계를 지정하면 nextInt 메소드의 성능이 약간 nextInt ,이 성능 저하는 bound 가 최대 int 값의 절반 bound 가까워짐에 따라 더 두드러지게됩니다.

암호로 안전한 의사 난수 생성

RandomThreadLocalRandom 은 일상적으로 사용하기에 충분하지만 큰 문제가 있습니다. 선형 합동 생성기를 기반으로합니다. 알고리즘은 출력이 다소 쉽게 예측 될 수 있습니다. 따라서이 두 클래스는 키 생성과 같은 암호화 용도에 적합 하지 않습니다 .

예측하기가 매우 어려운 PRNG가 필요한 상황에서 java.security.SecureRandom 을 사용할 수 있습니다. 이 클래스의 인스턴스에 의해 생성 된 난수를 예측하는 것은 클래스를 암호 학적으로 안전한 것으로 분류하기에 충분합니다.

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 은 2 48Random 주기에 비해 2 160 의 거대한 기간을 갖습니다. 그러나 Mersenne TwisterXorshift 와 같은 Random 과 다른 선형 PRNG보다 상당히 느린 단점이 있습니다.

SecureRandom의 구현은 플랫폼과 프로 바이더에 의존하고 있습니다. 디폴트의 SecureRandom ( sun.security.provider.SecureRandom 내의 SUN 프로 바이더에 의해 지정된다).

  • 유닉스 계열 시스템에서 /dev/random 및 / 또는 /dev/urandom 됩니다.
  • Windows에서 CryptoAPI의 CryptGenRandom() 호출을 시드 합니다 .

중복되지 않은 난수 선택

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

이 메서드는 요청한 길이의 크기를 가진 배열을 반복하여 작동하고 가능한 숫자의 나머지 길이를 찾습니다. 가능한 번호 newRandSpot 의 임의의 수를 설정하고 그 번호를 촬영되지 않은 숫자 왼쪽에서 찾습니다. 범위를 반복하고 해당 숫자가 이미 사용되었는지 확인하기 위해 점검합니다.


예를 들어 범위가 5이고 길이가 3이고 이미 숫자 2를 선택한 경우 남은 숫자가 4 개이므로 1에서 4 사이의 임의의 숫자를 얻고 숫자를 건너 뛰는 범위 (5)를 반복합니다. 우리는 이미 사용했습니다 (2).

이제 1과 4 사이에서 선택되는 다음 숫자가 3이라고 가정 해 봅시다. 첫 번째 루프에서 아직 얻지 못한 1을 얻습니다. 3에서 1을 제거 할 수 있습니다 2. 이제 두 번째 루프에서 2를 얻습니다 그래서 우리는 아무것도하지 않습니다. 우리는 4가 될 때까지이 패턴을 따른다. 1을 제거하면 0이되어 새로운 randomNumber를 4로 설정한다.

지정된 시드로 난수 생성하기

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

동일한 시드를 사용하여 임의의 숫자를 생성 할 때마다 동일한 숫자가 반환되므로 모든 Random 인스턴스에 대해 서로 다른 시드를 설정하면 중복되는 숫자로 끝내지 않으려면 좋은 생각입니다.

모든 호출에 대해 다른 Long 을 얻는 좋은 방법은 System.currentTimeMillis() .

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

apache-common lang3을 사용하여 난수 생성하기

우리는 org.apache.commons.lang3.RandomUtils 를 사용하여 한 줄로 난수를 생성 할 수 있습니다.

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

nextInt(int startInclusive, int endExclusive) 메소드는 범위를 취합니다.

int와는 별도로이 클래스를 사용하여 long , double , floatbytes 를 임의로 생성 할 수 있습니다.

RandomUtils 클래스에는 다음 메소드가 포함되어 있습니다.

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
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow