rand () % 6이 편향된 이유는 무엇입니까?


109

std :: rand 사용 방법을 읽을 때 cppreference.com 에서이 코드를 찾았습니다.

int x = 7;
while(x > 6) 
    x = 1 + std::rand()/((RAND_MAX + 1u)/6);  // Note: 1+rand()%6 is biased

오른쪽의 표현에 문제가 있습니까? 그것을 시도하고 완벽하게 작동합니다.


24
주사위 에 사용 하는 것이 훨씬 더 좋습니다std::uniform_int_distribution
Caleth

1
@Caleth 예,이 코드가 왜 '잘못'되었는지 이해하는 것입니다 ..
yO_

15
"바이어스"에 "잘못"변경
Cubbi

3
rand()일반적인 구현에서는 너무 나쁘기 때문에 xkcd RNG를 사용할 수도 있습니다 . 따라서 rand().
CodesInChaos

3
저는이 글을 썼습니다 (댓글이 아니라 @Cubbi입니다). 당시 제가 염두에 둔 것은 Pete Becker의 답변이 설명하는 것입니다. (참고로, 이것은 기본적으로 libstdc ++의 알고리즘과 동일한 알고리즘 uniform_int_distribution입니다.)
TC

답변:


136

두 가지 문제가 있습니다 rand() % 6( 두 문제 1+모두에 영향을주지 않음).

첫째, 여러 답변에서 지적했듯이의 하위 비트 rand()가 적절하게 균일하지 않으면 나머지 연산자의 결과도 균일하지 않습니다.

둘째,에 의해 생성 된 고유 값의 수가 rand()6의 배수가 아니면 나머지는 높은 값보다 더 낮은 값을 생성합니다. rand()완벽하게 분포 된 값을 반환 하더라도 마찬가지 입니다.

극단적 인 예로서 rand()범위에서 균일하게 분포 된 값 을 생성하는 척 하십시오 [0..6]. 해당 값의 나머지를 살펴보면 rand()범위의 값을 반환 할 때 [0..5]나머지는 범위 에 균일하게 분포 된 결과를 생성합니다 [0..5]. rand()6을 rand() % 6반환 하면 0을 반환 한 것처럼 0 rand()을 반환합니다. 따라서 다른 값보다 두 배 많은 0이있는 분포를 얻습니다.

두 번째는 것입니다 실제 와 문제 rand() % 6.

이 문제를 피하는 방법은 균일하지 않은 중복을 생성하는 값 을 버리는 것입니다. 보다 작거나 같은 6의 가장 큰 배수를 계산하고, 그 배수보다 크거나 같은 값을 반환 RAND_MAX할 때마다 rand()이를 거부하고 필요한만큼 여러 번`rand ()를 다시 호출합니다.

그래서:

int max = 6 * ((RAND_MAX + 1u) / 6)
int value = rand();
while (value >= max)
    value = rand();

이것은 무슨 일이 일어나고 있는지 더 명확하게 보여주기 위해 문제의 코드의 다른 구현입니다.


2
나는이 사이트에서 적어도 한 명은 이것에 대한 논문을 만들겠다고 약속했지만 샘플링과 거절 중요한 순간을 잃을 있다고 생각 합니다 . 예를 들어 분산을 과도하게 확장합니다.
Bathsheba

30
rand_max가 32768 인 경우이 기술이 도입하는 편향의 정도를 그래프로 만들었는데, 이는 일부 구현에 있습니다. ericlippert.com/2013/12/16/…
Eric Lippert

2
@Bathsheba : 일부 거부 기능이이를 유발할 수 있다는 것은 사실이지만이 간단한 거부는 균일 한 IID를 다른 균일 한 IID 분포로 변환합니다. 어떤 비트도 전달되지 않으므로 독립적이며 모든 샘플은 균일 성을 보여주기 위해 동일하고 사소한 동일한 거부를 사용합니다. 그리고 균일 적분 랜덤 변수의 더 높은 모멘트는 그 범위에 의해 완전히 정의됩니다.
MSalters

4
@MSalters : 첫 번째 문장은 실제 생성기에 대해 정확 하고 의사 생성기에는 반드시 적용되지 않습니다. 은퇴하면 이것에 대해 논문을 쓸 것입니다.
Bathsheba

2
@Anthony 주사위를 생각 해보세요. 1에서 3 사이의 임의의 숫자를 원하고 표준 6면 주사위 만 있습니다. 4-6을 굴리면 3을 빼서 얻을 수 있습니다. 그러나 대신에 1과 5 사이의 숫자를 원한다고 가정 해 봅시다. 6을 굴릴 때 5를 빼면 다른 숫자보다 2 배 많은 1이됩니다. 이것이 기본적으로 cppreference 코드가하는 일입니다. 올바른 방법은 6을 다시 굴리는 것입니다. 그것이 Pete가 여기서하는 일입니다. 주사위를 나누어 각 숫자를 같은 수의 방법으로 굴리고 짝수 분할에 맞지 않는 숫자를 다시 굴립니다
Ray

19

여기에 숨겨진 깊이가 있습니다.

  1. 작은의 사용 u에서 RAND_MAX + 1u. 유형으로 RAND_MAX정의되며 int가능한 가장 큰 int. 의 동작은 RAND_MAX + 1될 것입니다 정의되지 않은 사용자가 넘쳐 할 것 같은 경우에 signed유형입니다. 쓰기 1u세력의 변환 입력 RAND_MAX에를 unsigned너무 오버 플로우를 미연에 방지.

  2. 의 사용 % 6 (그러나 모든 구현에 std::rand나는 본 적이 없습니다 위 제시된 대안을 넘어 추가 통계에 편차를 소개합니다). % 6위험한 경우는 숫자 생성기가 하위 비트에 상관 관계 평야를 갖는 경우입니다. 예를 들어 in의 다소 유명한 IBM 구현 (C에서)과 rand같이 상위 및 하위 비트를 "최종 융성". 추가 고려 사항은 6이 매우 작다는 것입니다. RAND_MAX이므로이 RAND_MAX6의 배수가 아니면 최소한의 효과 가있을 것입니다.

결론적으로 요즘에는 다루기 쉽기 때문에 % 6. 생성기 자체가 도입 한 것 이상의 통계적 이상을 도입 할 가능성은 없습니다. 여전히 의심스러운 경우 생성기를 테스트 하여 사용 사례에 적합한 통계 속성이 있는지 확인하십시오.


12
% 6에서 생성 된 고유 값의 수가 rand()6의 배수가 아닐 때마다 편향된 결과를 생성합니다 . 비둘기 구멍 원리. 물론, 편향은 RAND_MAX6보다 훨씬 클 때 작지만 거기에 있습니다. 그리고 더 큰 목표 범위의 경우 효과는 물론 더 큽니다.
Pete Becker

2
@PeteBecker : 사실, 나는 그것을 분명히해야합니다. 그러나 정수 분할 자르기 효과로 인해 샘플 범위가 RAND_MAX에 가까워지면 비둘기 홀링도 발생합니다.
Bathsheba

2
@Bathsheba는 잘림 효과가 6보다 큰 결과를 가져와 전체 작업을 반복적으로 실행하지 않습니까?
Gerhardh

1
@Gerhardh : 맞습니다. 사실, 그것은 정확히 결과로 이어 집니다x==7 . 기본적으로 범위 [0, RAND_MAX]를 7 개의 하위 범위, 같은 크기의 6 개와 끝에 하나 더 작은 하위 범위 로 나눕니다 . 마지막 하위 범위의 결과는 무시됩니다. 이런 식으로 끝에 두 개의 더 작은 하위 범위를 가질 수 없다는 것은 상당히 분명합니다.
MSalters

@MSalters : 그렇습니다. 그러나 다른 방법은 잘림으로 인해 여전히 어려움을 겪습니다. 내 가설은 통계적 함정을 이해하기가 더 어렵 기 때문에 후자의 경우 민속이 통통하다는 것입니다!
Bathsheba

13

이 예제 코드 std::rand는 그것이 당신이 그것을 볼 때마다 당신의 눈썹을 올려야하는 레거시화물 컬트 balderdash의 사례를 보여줍니다 .

여기에는 몇 가지 문제가 있습니다.

계약 사람들은 일반적으로 가난한 불운 한 영혼이 더 좋은 모르는 사람들도-가정하고 정확하게 다음에 생각하지 않을 것이다 용어-IS rand로부터 샘플 균일 한 분포를 0에서 정수에, 1, 2, ..., RAND_MAX, 각 호출은 독립적 인 샘플을 생성합니다 .

첫 번째 문제는 가정 된 계약 (각 호출에서 독립적 인 균일 한 무작위 샘플)이 실제로 문서에 나와있는 내용이 아니라는 것입니다. 실제로 구현은 역사적으로 가장 작은 독립 시뮬레이션조차 제공하지 못했습니다. 예를 들어, C99 §7.20.2.1 ' rand기능'은 정교하지 않고 다음과 같이 말합니다.

rand함수는 0에서 RAND_MAX. 까지 범위의 의사 난수 정수 시퀀스를 계산합니다 .

의사 난수는 정수가 아닌 함수 (또는 함수 계열)의 속성 이지만 ISO 관료조차도 언어를 남용하는 것을 막지는 못 하기 때문에 이것은 의미없는 문장 입니다. 결국, 그것에 대해 화를 낼 유일한 독자 rand는 뇌 세포가 썩는다는 두려움 때문에 문서를 읽는 것보다 더 잘 알고 있습니다.

C의 일반적인 역사적 구현은 다음과 같이 작동합니다.

static unsigned int seed = 1;

static void
srand(unsigned int s)
{
    seed = s;
}

static unsigned int
rand(void)
{
    seed = (seed*1103515245 + 12345) % ((unsigned long)RAND_MAX + 1);
    return (int)seed;
}

이는 단일 샘플이 균일 한 임의 시드 (의 특정 값에 따라 다름) 하에서 균일하게 분포 될 수 있지만RAND_MAX 연속 호출에서 짝수와 홀수 정수를 번갈아 가며

int a = rand();
int b = rand();

이 표현식 (a & 1) ^ (b & 1)은 100 % 확률로 1을 산출합니다. 이는 짝수 및 홀수 정수에서 지원되는 모든 분포에 대한 독립적 인 랜덤 샘플 의 경우가 아닙니다 . 따라서, '더 나은 무작위성'이라는 애매한 짐승을 쫓기 위해 하위 비트를 버려야한다는화물 컬트가 등장했습니다. (스포일러 경고 : 이것은 전문 용어가 아닙니다. 이것은 당신이 읽고있는 산문이 그들이 무엇에 대해 말하고 있는지 모르거나 당신 이 단서가없고 굴욕적 이라고 생각 한다는 신호입니다.)

두 번째 문제는 각 호출이 0, 1, 2,…, RAND_MAX에서 균일 한 임의 분포독립적으로 샘플링 을 수행 하더라도 의 결과 rand() % 6가 주사위처럼 0, 1, 2, 3, 4, 5에 균일하게 분포되지 않는다는 것입니다. RAND_MAX-1 모듈로 6에 합동 하지 않는 한 롤링 . 간단한 반례 : If RAND_MAX= 6 rand()이면 모든 결과는 1/7 확률이 같지만에서 rand() % 6결과 0은 확률이 2/7이고 다른 모든 결과는 확률이 1/7입니다. .

이렇게하는 올바른 방법이 거부 샘플링이다 반복적 독립적 균일 무작위 샘플을 그리는 s0, 1, 2 행, ..., RAND_MAX거부 성과 0, 1, 2, ..., (예를 들면) ((RAND_MAX + 1) % 6) - 1는 하나 얻을 -if 다시 시작하십시오. 그렇지 않으면 yield s % 6.

unsigned int s;
while ((s = rand()) < ((unsigned long)RAND_MAX + 1) % 6)
    continue;
return s % 6;

이런 식으로, rand()우리가 받아들이는 결과 세트는 6으로 균등하게 나눌 수 있으며, 각각의 가능한 결과는에서 허용s % 6 되는 동일한 수의 결과로 얻어 지므로 균등하게 분배 되면 . 시행 횟수 에는 제한 이 없지만 예상 횟수 는 2 미만이며 성공 확률은 시행 횟수에 따라 기하 급수적으로 증가합니다.rand()rand()s

6 미만의 각 정수에 동일한 수의 결과를 매핑하는 경우 거부 하는 결과의 선택 rand()은 중요하지 않습니다. cppreference.com의 코드는 위의 첫 번째 문제 때문에 다른 선택을합니다. 의 출력의 분포 또는 독립성 rand()및 실제로 하위 비트는 '충분히 무작위로 보이지 않는'패턴을 나타 냈습니다 (다음 출력이 이전 출력의 결정적 기능이라는 점에 유의하지 마십시오).

독자를위한 연습 문제 : cppreference.com의 코드가 rand()0, 1, 2,…,에서 균일 한 분포를 산출하는 경우 주사위 굴림에서 균일 한 분포를 산출 함을 증명하십시오 RAND_MAX.

독자를위한 연습 : 왜 하나 또는 다른 하위 집합을 거부하는 것을 선호 할 수 있습니까? 두 경우의 각 시행에 대해 어떤 계산이 필요합니까?

세 번째 문제는 시드 공간이 너무 작아서 시드가 균일하게 분포되어 있어도 프로그램과 한 가지 결과에 대한 지식으로 무장 한 적이 있지만 시드가없는 적이 시드와 후속 결과를 쉽게 예측할 수 있으므로 그렇지 않은 것처럼 보입니다. 결국 무작위. 따라서 이것을 암호화에 사용하는 것에 대해 생각조차하지 마십시오.

4 살짜리 사촌과 함께 주사위 놀이를하기 위해 std::uniform_int_distribution항상 인기있는 Mersenne 트위스터와 같은 적절한 임의의 장치와 좋아하는 임의의 엔진을 사용 하여 멋진 오버 엔지니어링 된 경로와 C ++ 11의 수업을 std::mt19937진행할 수 있습니다. 암호화 키 자료를 생성하는 데 적합해야합니다. Mersenne 트위스터는 끔찍한 공간을 차지하기 때문에 수 킬로바이트 상태가 CPU 캐시에 음란 한 설정 시간으로 혼란을 일으키고 있습니다. 따라서 예를 들어 다음 과 같은 병렬 몬테카를로 시뮬레이션 에도 좋지 않습니다. 재현 가능한 하위 계산 트리; 그 인기는 주로 눈에 띄는 이름에서 비롯된 것 같습니다. 그러나이 예제와 같이 장난감 주사위를 굴리는 데 사용할 수 있습니다!

또 다른 접근 방식은 간단한 빠른 키 삭제 PRNG 와 같은 작은 상태의 간단한 암호화 의사 난수 생성기를 사용 하거나 확신이있는 경우 AES-CTR 또는 ChaCha20과 같은 스트림 암호를 사용하는 것입니다 ( 예 : Monte Carlo 시뮬레이션에서 자연 과학에 대한 연구) 국가가 타협 할 경우 과거 결과를 예측하는 데 불리한 결과가 없다는 것입니다.


4
"음란 한 설정 시간"어쨌든 하나 이상의 난수 생성기 (스레드 당)를 사용해서는 안되므로 프로그램이 너무 오래 실행되지 않는 한 설정 시간이 분할됩니다.
JAB

2
질문의 루프가 정확히 동일한 (RAND_MAX + 1 )% 6값에 대해 정확히 동일한 거부 샘플링을 수행하고 있다는 사실을 이해하지 못한 경우 BTW에 반대표를 던집니다 . 가능한 결과를 어떻게 세분화 하는지 는 중요하지 않습니다 . [0, RAND_MAX)허용되는 범위의 크기가 6의 배수 인 한 범위의 어느 곳에서나 거부 할 수 있습니다 . 지옥, 모든 결과를 거부 할 수 x>6있으며 %6더 이상 필요 하지 않습니다.
MSalters

12
이 답변에 만족하지 않습니다. Rants는 좋을 수 있지만 잘못된 방향으로 가고 있습니다. 예를 들어 "더 나은 임의성"이 기술 용어가 아니며 의미가 없다고 불평합니다. 이것은 절반 사실입니다. 예, 기술 용어는 아니지만 문맥 상 완벽하게 의미있는 속기입니다. 그러한 용어의 사용자가 무지하거나 악의적이라는 것을 암시하는 것은 그 자체로 이러한 것 중 하나입니다. "좋은 임의성"은 정확하게 정의하기가 매우 어려울 수 있지만 함수가 임의성 속성이 더 좋거나 더 나쁜 결과를 생성 할 때 파악하는 것은 쉽습니다.
Konrad Rudolph

3
이 답변이 마음에 들었습니다. 약간의 폭언이지만 좋은 배경 정보가 많이 있습니다. REAL 전문가는 하드웨어 랜덤 생성기 만 사용한다는 점을 명심하십시오. 문제는 그렇게 어렵습니다.
Tiger4Hire

10
저에게는 그 반대입니다. 좋은 정보가 포함되어 있지만 의견이 아닌 다른 것으로 나오기에는 너무 많은 호언이 있습니다. 제쳐두고 유용합니다.
Mr Lister

2

나는 경험이 풍부한 C ++ 사용자는 아니지만 실제로 std::rand()/((RAND_MAX + 1u)/6)편견이 적은 다른 답변 이 1+std::rand()%6사실인지 확인하고 싶었습니다. 그래서 두 가지 방법에 대한 결과를 표로 만드는 테스트 프로그램을 작성했습니다 (C ++를 오랫동안 작성하지 않았습니다. 확인하십시오). 코드를 실행하기위한 링크는 여기에 있습니다 . 또한 다음과 같이 재현됩니다.

// Example program
#include <cstdlib>
#include <iostream>
#include <ctime>
#include <string>

int main()
{
    std::srand(std::time(nullptr)); // use current time as seed for random generator

    // Roll the die 6000000 times using the supposedly unbiased method and keep track of the results

    int results[6] = {0,0,0,0,0,0};

    // roll a 6-sided die 20 times
    for (int n=0; n != 6000000; ++n) {
        int x = 7;
        while(x > 6) 
            x = 1 + std::rand()/((RAND_MAX + 1u)/6);  // Note: 1+rand()%6 is biased

        results[x-1]++;
    }

    for (int n=0; n !=6; n++) {
        std::cout << results[n] << ' ';
    }

    std::cout << "\n";


    // Roll the die 6000000 times using the supposedly biased method and keep track of the results

    int results_bias[6] = {0,0,0,0,0,0};

    // roll a 6-sided die 20 times
    for (int n=0; n != 6000000; ++n) {
        int x = 7;
        while(x > 6) 
            x = 1 + std::rand()%6;

        results_bias[x-1]++;
    }

    for (int n=0; n !=6; n++) {
        std::cout << results_bias[n] << ' ';
    }
}

그런 다음이 결과를 가져와 chisq.testR 의 함수를 사용하여 카이 제곱 테스트를 실행하여 결과가 예상과 크게 다른지 확인했습니다. 이 stackexchange 질문은 카이-제곱 테스트를 사용하여 다이 공정성을 테스트 하는 방법에 대해 자세히 설명 합니다. 다이가 공정한지 어떻게 테스트 할 수 있습니까? . 다음은 몇 번 실행 한 결과입니다.

> ?chisq.test
> unbias <- c(100150, 99658, 100319, 99342, 100418, 100113)
> bias <- c(100049, 100040, 100091, 99966, 100188, 99666 )

> chisq.test(unbias)

Chi-squared test for given probabilities

data:  unbias
X-squared = 8.6168, df = 5, p-value = 0.1254

> chisq.test(bias)

Chi-squared test for given probabilities

data:  bias
X-squared = 1.6034, df = 5, p-value = 0.9008

> unbias <- c(998630, 1001188, 998932, 1001048, 1000968, 999234 )
> bias <- c(1000071, 1000910, 999078, 1000080, 998786, 1001075   )
> chisq.test(unbias)

Chi-squared test for given probabilities

data:  unbias
X-squared = 7.051, df = 5, p-value = 0.2169

> chisq.test(bias)

Chi-squared test for given probabilities

data:  bias
X-squared = 4.319, df = 5, p-value = 0.5045

> unbias <- c(998630, 999010, 1000736, 999142, 1000631, 1001851)
> bias <- c(999803, 998651, 1000639, 1000735, 1000064,1000108)
> chisq.test(unbias)

Chi-squared test for given probabilities

data:  unbias
X-squared = 7.9592, df = 5, p-value = 0.1585

> chisq.test(bias)

Chi-squared test for given probabilities

data:  bias
X-squared = 2.8229, df = 5, p-value = 0.7273

내가 한 세 번의 실행에서 두 방법의 p- 값은 항상 유의성을 테스트하는 데 사용 된 일반적인 알파 값 (0.05)보다 컸습니다. 이것은 우리가 그들 중 어느 쪽도 편향되지 않는다는 것을 의미합니다. 흥미롭게도, 편향되지 않은 방법은 지속적으로 더 낮은 p- 값을 가지며, 이는 실제로 더 편향 될 수 있음을 나타냅니다. 주의 사항은 내가 3 번만 뛰었다는 것입니다.

업데이트 : 내 답변을 작성하는 동안 Konrad Rudolph는 동일한 접근 방식을 취하지 만 매우 다른 결과를 얻는 답변을 게시했습니다. 나는 그의 대답에 대해 언급 할만한 명성이 없기 때문에 여기서 다루려고합니다. 첫째, 가장 중요한 것은 그가 사용하는 코드가 실행될 때마다 난수 생성기에 동일한 시드를 사용한다는 것입니다. 씨앗을 바꾸면 실제로 다양한 결과를 얻을 수 있습니다. 둘째, 시드를 변경하지 않고 시행 횟수를 변경하면 다양한 결과를 얻을 수 있습니다. 내가 의미하는 바를 확인하려면 한 단계 씩 늘리거나 줄이십시오. 셋째, 예상 값이 정확하지 않은 경우 정수 절단 또는 반올림이 진행됩니다. 차이를 만드는 것만으로는 충분하지 않지만 거기에 있습니다.

기본적으로 요약하면 그는 잘못된 결과를 얻을 수있는 올바른 씨앗과 시도 횟수를 얻었습니다.


귀하의 구현에는 귀하의 오해로 인해 치명적인 결함이 있습니다. 인용 된 구절이 와 비교 되지 않습니다 . 오히려 나머지를 직접 취하여 거부 샘플링 과 비교 합니다 (설명은 다른 답변 참조). 결과적으로 두 번째 코드가 잘못되었습니다 ( 루프는 아무 작업도 수행하지 않음). 통계 테스트에도 문제가 있습니다 (견고성을 위해 테스트를 반복 할 수없고 수정을 수행하지 않은 것 등). rand()%6rand()/(1+RAND_MAX)/6while
Konrad Rudolph

1
@KonradRudolph 귀하의 답변에 대해 언급 할 담당자가 없으므로 업데이트로 추가했습니다. 또한 잘못된 결과를 제공하는 매 실행마다 설정된 시드와 시도 횟수를 사용한다는 점에서 치명적인 결함이 있습니다. 다른 씨앗으로 반복을 실행했다면 그것을 잡았을 것입니다. 하지만 그래, 당신은 루프가하는 동안 아무것도 해결되지 않습니다, 그러나 그것은 또한 특정 코드 블럭의 결과를 변경하지 않습니다
anjama

나는 실제로 반복을 실행했습니다. 씨는 의도적으로 임의의 씨앗을 설정하기 때문에 설정되지 않은 std::srand(그리고 전혀 사용 <random>) 방식을 따르는 표준에 할 매우 어려운 없습니다 난 나머지 코드에서 떨어지다과의 복잡함을 원하지 않았다. 또한 계산과 관련이 없습니다. 시뮬레이션에서 동일한 시퀀스를 반복하는 것은 전적으로 허용됩니다. 물론 다른 씨앗 다른 결과를 낳고 일부는 중요하지 않습니다. 이는 p- 값이 정의 된 방식에 따라 전적으로 예상됩니다.
Konrad Rudolph

1
쥐, 나는 내 반복에서 실수를 저질렀다. 그리고 당신 말이 맞습니다. 반복 실행의 95 번째 분위수는 p = 0.05에 아주 가깝습니다. 요컨대, 내 표준 라이브러리 구현 std::rand은 무작위 시드 범위에서 d6에 대해 놀랍도록 좋은 동전 던지기 시뮬레이션을 산출합니다.
Konrad Rudolph

1
통계적 유의성 은 이야기의 일부일뿐입니다. 귀무 가설 (균일 분포)과 대립 가설 (모듈로 바이어스) RAND_MAX이 있습니다. 실제로 모듈로 바이어스 의 효과 크기 를 결정 하는를 선택하여 색인 된 대립 가설 패밀리입니다 . 통계적 유의성은 귀무 가설 하에서 잘못 기각 할 확률입니다. 통계적 검정력 은 무엇입니까? 대립 가설 하에서 테스트 가 귀무 가설을 올바르게 기각 할 확률 은 무엇입니까 ? rand() % 6RAND_MAX = 2 ^ 31-1 일 때 이런 식으로 감지 하시겠습니까 ?
Squeamish Ossifrage

2

난수 생성기는 이진수 스트림에서 작업하는 것으로 생각할 수 있습니다. 생성기는 스트림을 청크로 분할하여 숫자로 변환합니다. 경우] std:rand함수는로 작동 RAND_MAX한 다음, 각 슬라이스에 15 비트를 사용하고, 32767.

0에서 32767 사이의 숫자 모듈을 가져 오면 5462 개의 '0'과 '1'이 있지만 '2', '3', '4', '5'는 5461 개뿐입니다. 따라서 결과는 편향되어 있습니다. RAND_MAX 값이 클수록 편향이 적지 만 피할 수 없습니다.

편향되지 않은 것은 [0 .. (2 ^ n) -1] 범위의 숫자입니다. 3 비트를 추출하고 0..7 범위의 정수로 변환하고 6과 7을 거부하여 0..5 범위에서 (이론적으로) 더 나은 숫자를 생성 할 수 있습니다.

하나는 비트 스트림의 모든 비트가 스트림의 위치 또는 다른 비트의 값에 관계없이 '0'또는 '1'이 될 동일한 기회를 갖기를 바랍니다. 이것은 실제로 매우 어렵습니다. 소프트웨어 PRNG의 다양한 구현은 속도와 품질간에 서로 다른 절충안을 제공합니다. 같은 선형 합동 발생기 std::rand는 최저 품질을 위해 가장 빠른 속도를 제공합니다. 암호화 생성기는 최저 속도로 최고 품질을 제공합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.