java - 클래스 - 자바 문자열 랜덤 출력



연속 한 수를 가지는 java.util.Random를 시드한다 (1)

가능한 한 많이, RNG의 씨앗은 그 자체가 무작위이어야합니다. 당신이 사용하는 씨앗은 1-2 비트 차이 만있을 것입니다.

하나의 프로그램에 2 개의 별도 RNG를 만드는 것이 거의 없습니다. 코드가 의미가있는 상황 중 하나가 아닙니다.

하나의 RNG를 만들고 다시 사용하면이 문제가 발생하지 않습니다.

mmyers의 의견에 대한 응답으로

이 경우 5와 6을 왜 선택하는지 설명 할 수있을 정도로 java.util.Random을 알게됩니까?

답은 선형 합동 RNG 인 java.util.Random의 소스 코드에 있습니다. 생성자에서 시드를 지정하면 다음과 같이 조작됩니다.

seed = (seed ^ 0x5DEECE66DL) & mask;

여기서 마스크는 단순히 하위 48 비트를 유지하고 다른 비트는 무시합니다.

실제 무작위 비트를 생성 할 때이 시드는 다음과 같이 조작됩니다.

randomBits = (seed * 0x5DEECE66DL + 0xBL) & mask;

이제 Parker 에서 사용 된 씨앗이 순차적 (0-1499)이었고 한 번 사용 된 다음 폐기 된 것으로 간주하면 처음 네 개의 씨드가 다음과 같은 네 가지 임의 비트 세트를 생성했습니다.

101110110010000010110100011000000000101001110100
101110110001101011010101011100110010010000000111
101110110010110001110010001110011101011101001110
101110110010011010010011010011001111000011100001

상위 10 비트는 각각의 경우에 indentical입니다. 이것은 단지 0-7 (단지 약간의 비트가 필요함)의 값을 생성하기를 원하기 때문에 문제이며, RNG 구현은 상위 비트를 오른쪽으로 시프트하고 하위 비트를 폐기함으로써 이것을 수행합니다. 이는 일반적으로 높은 비트가 낮은 비트보다 무작위이기 때문에 발생합니다. 이 경우에는 종자 데이터가 좋지 않아서가 아닙니다.

마지막으로,이 비트가 우리가 얻는 10 진수 값으로 변환하는 방법을 보려면 java.util.Random이 n이 2의 거듭 제곱 인 경우 특수한 경우를 만들어야한다는 것을 알아야합니다. 31 개의 임의 비트 ( 48 이상), 그 값에 n을 곱한 다음 31 비트를 오른쪽으로 시프트합니다.

8을 곱하면 (이 예에서 n 값) 왼쪽으로 3 칸 이동하는 것과 같습니다. 따라서이 절차의 최종 효과는 31 비트 28 개를 오른쪽으로 이동하는 것입니다. 위의 4 가지 예에서 비트 패턴 101 (또는 10 진수 5)이 남습니다.

만약 우리가 RNG를 하나의 값으로 버리지 않았다면, 시퀀스가 ​​분기하는 것을 볼 수 있습니다. 위의 4 개의 시퀀스는 모두 5로 시작하지만 두 번째 값은 각각 6, 0, 2 및 4입니다. 처음 씨앗의 작은 차이가 영향력을 갖기 시작합니다.

업데이트 된 질문에 대한 답변 : java.util.Random 은 스레드로부터 안전합니다. 여러 스레드에서 하나의 인스턴스를 공유 할 수 있으므로 여러 인스턴스를 가질 필요가 없습니다. 실제로 여러 개의 RNG 인스턴스가 있어야하는 경우 서로 독립적 으로 시드되도록해야합니다. 그렇지 않으면 출력을 독립적으로 신뢰할 수 없습니다.

이런 종류의 효과를 얻는 이유는 java.util.Random이 최고의 RNG가 아니기 때문입니다. 그것은 간단하고, 꽤 빠르며, 너무 가깝게 보지 않으면 합리적으로 무작위입니다. 그러나 출력에 대해 심각한 테스트 를 실행하면 결함이 있음을 알 수 있습니다. 그걸 시각적으로 볼 수 있습니다.

좀 더 랜덤 한 RNG가 필요한 경우 java.security.SecureRandom 을 사용할 수 있습니다. 조금 느리지 만 제대로 작동합니다. 한 가지 문제는 반복적이지 않다는 것입니다. 같은 seed를 가지는 2 개의 SecureRandom 인스턴스는 같은 출력을 제공하지 않습니다. 이는 의도적으로 설계된 동작입니다.

그래서 다른 옵션은 무엇입니까? 이것은 내가 내 자신의 라이브러리를 연결하는 곳입니다. 여기에는 SecureRandom보다 빠르며 java.util.Random보다 무작위 인 3 개의 반복 가능한 의사 RNG가 포함됩니다. 나는 그들을 발명하지 않았고, 나는 원래의 C 버전에서 이식했다. 그들은 모두 스레드로부터 안전합니다.

진화론 적 계산 코드를 위해 더 나은 것이 필요했기 때문에 이러한 RNG를 구현했습니다. 원래의 간단한 대답에 따라이 코드는 멀티 스레드이지만 모든 스레드간에 공유되는 단일 RNG 인스턴스 만 사용합니다.

다음 코드 줄을 겪고있는 버그를 단순화했습니다.

    int[] vals = new int[8];
    for (int i = 0; i < 1500; i++)
        vals[new Random(i).nextInt(8)]++;
    System.out.println(Arrays.toString(vals));

출력은 [0, 0, 0, 0, 0, 1310, 190, 0]입니다.

이 무작위 씨앗을 연속 숫자를 선택하고 다음 2의 힘으로 nextInt를 사용하는 유물입니까? 그렇다면 내가 알아야 할 다른 함정이 있습니까? 그렇지 않다면 내가 뭘 잘못하고 있습니까? (나는 위의 문제에 대한 해결책을 찾고 있지 않으며, 그 밖의 무엇이 잘못 될 수 있는지에 대해서만 이해하고있다)

댄, 잘 쓰여진 분석. javadoc은 숫자가 계산되는 방법에 대해 매우 명시 적이므로이 문제와 관련하여 다음과 같은 다른 예외가있는 것만 큼 신비가 아닙니다. 연속 씨앗에 대한 문서를 전혀 볼 수 없었습니다. java.util.Random에 대한 경험이있는 누군가가 다른 일반적인 함정을 지적 할 수 있기를 바란다.

코드에 관해서는, 여러 병렬 에이전트가 반복적으로 임의의 동작을하는 것이 필요합니다.이 동작은 첫 번째 단계로 열거 형 요소를 선택할 수 있습니다. 일단이 동작을 발견하면, 씨앗은 모두 알려진 시드에서 생성 된 마스터 무작위 객체에서 왔습니다. 프로그램의 이전 (순차적으로 시드 된) 버전에서는 모든 동작이 nextInt에 대한 첫 번째 호출 이후에 신속하게 분기되었으므로 프로그램 동작을 RNG 라이브러리로 축소하는 데 꽤 오래 걸렸습니다. 미래의 상황.





random