C ++ 11에서 난수 생성 : 생성 방법, 작동 원리 [닫은]


102

나는 최근에 C ++ 11에서 난수를 생성하는 새로운 방법을 발견했지만 그것에 대해 읽은 논문 을 소화 할 수 없었 습니다 ( 엔진 , 분포 와 같은 수학 용어 , "모든 정수가 똑같이 생성 될 가능성이있는 곳 ").

누구든지 설명해 주시겠습니까

  • 그들은 무엇인가?
  • 무슨 뜻입니까?
  • 생성하는 방법?
  • 어떻게 작동합니까?
  • 기타

난수 생성에 대한 하나의 FAQ에서 모든 것을 호출 할 수 있습니다.


6
배포판이 무엇인지 모른 채 RNG에 대해 묻는 것은 표현식이 무엇인지 알지 못한 채 표현식 파서에 대해 묻는 것과 같습니다. C ++ 11의 RNG 라이브러리는 통계를 알고있는 사람들을 대상으로합니다. rand, 당신은 몇 가지 기본적인 통계와 RNG 개념에 대해 위키피디아를 훑어보아야합니다. 그렇지 않으면 그것 <random>의 다양한 조각 의 근거 와 사용법 을 설명하기가 정말 어려울 것 입니다.
Matteo Italia

26
@Matteo : 거의 없습니다. 어린이는 분포가 무엇인지 이해하지 않고도 주사위가 난수를 생성한다는 개념을 이해할 수 있습니다.
Benjamin Lindley

3
@Benjamin : 그리고 그것이 그의 이해가 멈추는 곳입니다. 이것은 단지 첫 번째 단계 (엔진) 일 뿐이며, 왜 그들이 평평한 분포를 생성하는 것이 중요한지 이해하지 못하고 있습니다. 나머지 라이브러리는 분포 및 기타 통계 개념을 이해하지 못한 채 미스터리로 남아 있습니다.
Matteo Italia

답변:


142

질문은 완전한 답변을하기에는 너무 광범위하지만 몇 가지 흥미로운 점을 선택하겠습니다.

"동일한 가능성이있는"이유

동일한 확률로 숫자 0, 1, ..., 10을 생성하는 간단한 난수 생성기가 있다고 가정합니다 (이를 고전적인 것으로 생각하십시오 rand()). 이제 각각 동일한 확률을 가진 0, 1, 2 범위의 난수를 원합니다. 무릎을 꿇는 반응은 rand() % 3. 그러나 잠깐, 나머지 0과 1이 나머지 2보다 더 자주 발생하므로 이것은 올바르지 않습니다!

이것이 우리가 예에서 와 같이 균일 한 임의 정수의 소스를 가져와 원하는 분포로 바꾸는 적절한 분포 가 필요한 이유 Uniform[0,2]입니다. 이것을 좋은 도서관에 맡기는 것이 가장 좋습니다!

엔진

따라서 모든 무작위성의 중심에는 특정 간격에 걸쳐 균일하게 분포하고 이상적으로는 매우 긴 기간을 갖는 일련의 숫자를 생성하는 우수한 의사 난수 생성기가 있습니다. 의 표준 구현은 rand()종종 최고가 아니므로 선택하는 것이 좋습니다. Linear-congruential과 Mersenne twister는 두 가지 좋은 선택입니다 (LG는 실제로에서도 자주 사용됩니다 rand()). 다시 말하지만, 라이브러리가 처리하도록하는 것이 좋습니다.

작동 원리

쉬움 : 먼저 엔진을 설치하고 시드하십시오. 시드는 "무작위"숫자의 전체 시퀀스를 완전히 결정하므로 a /dev/urandom) 매번 다른 번호 (예 :에서 가져옴)를 사용 하고 b) 무작위 선택 시퀀스를 다시 생성하려는 경우 시드를 저장합니다.

#include <random>

typedef std::mt19937 MyRNG;  // the Mersenne Twister with a popular choice of parameters
uint32_t seed_val;           // populate somehow

MyRNG rng;                   // e.g. keep one global instance (per thread)

void initialize()
{
  rng.seed(seed_val);
}

이제 배포판을 만들 수 있습니다.

std::uniform_int_distribution<uint32_t> uint_dist;         // by default range [0, MAX]
std::uniform_int_distribution<uint32_t> uint_dist10(0,10); // range [0,10]
std::normal_distribution<double> normal_dist(mean, stddeviation);  // N(mean, stddeviation)

... 엔진을 사용하여 난수를 만드세요!

while (true)
{
  std::cout << uint_dist(rng) << " "
            << uint_dist10(rng) << " "
            << normal_dist(rng) << std::endl;

}

동시성

<random>기존 방식 보다 선호하는 또 하나의 중요한 이유 rand()는 난수 생성 스레드를 안전하게 만드는 방법이 이제 매우 명확하고 분명하다는 것입니다. 스레드 로컬 시드에 시드 된 자체 스레드 로컬 엔진을 각 스레드에 제공하거나 액세스를 동기화합니다. 엔진 개체에.

기타

  • codeguru에서 무작위로 TR1에 대한 흥미로운 기사 .
  • Wikipedia 에는 좋은 요약이 있습니다 (감사합니다, @Justin).
  • 원칙적으로 각 엔진은 result_type시드에 사용할 올바른 통합 유형 인 typedef a 를 사용해야합니다. 나는에 대한 씨앗을 강제로 저를 강요 한 번 버그 구현했다 생각 std::mt19937uint32_t64에를, 결국이 고정되어야하며, 당신이 말할 수 MyRNG::result_type seed_val있어 매우 쉽게 교체 엔진을합니다.

다시 한번, Kerrek은 내가 작업하던 것보다 훨씬 더 나은 대답으로 나를 때려 눕혔다. +1
Justin ᚅᚔᚈᚄᚒᚔ

@Justin : 나는 많은 것을 놓쳤을 것이라고 확신합니다.이 주제에 더 많은 측면을 자유롭게 추가하십시오! :-)
Kerrek SB

13
은 "어떻게 든 채 웁니다"의 경우, 생각 std::random_device보다는 언급 할 가치가있다/dev/urandom
Cubbi

2
의 예는 여기std::random_device 에서 찾을 수 있습니다 .
WKS

1
Wikipedia 기사의 코드는 버그가 있습니다. random과 random2는 동일합니다. 코드 조각의 주석에서 작성자가 <random>의 기능을 사용하는 방법을 이해하지 못하는 것이 분명합니다.
user515430

3

난수 생성기는 숫자가 주어지면 새로운 숫자를 제공하는 방정식입니다. 일반적으로 첫 번째 숫자를 제공하거나 시스템 시간과 같은 항목에서 가져온 숫자를 제공합니다.

새 번호를 요청할 때마다 이전 번호를 사용하여 방정식을 실행합니다.

난수 생성기는 다른 숫자보다 동일한 숫자를 더 자주 생성하는 경향이있는 경우 그다지 좋은 것으로 간주되지 않습니다. 즉, 1과 5 사이의 임의의 숫자를 원하고 다음과 같은 숫자 분포가있는 경우 :

  • 1 : 1 %
  • 2 : 80 %
  • 3 : 5 %
  • 4 : 5 %
  • 5 : 9 %

2는 다른 숫자보다 더 자주 생성되므로 다른 숫자보다 생성 될 가능성이 높습니다. 모든 숫자가 똑같다면 매번 각 숫자를 얻을 확률이 20 %입니다. 달리 말하면 위의 분포는 2가 선호되기 때문에 매우 고르지 않습니다. 모두 20 %의 분포는 균등합니다.

일반적으로 진정한 난수를 원한다면 난수 생성기보다는 날씨 또는 다른 자연 소스와 같은 것에서 데이터를 가져옵니다.


8
대부분의 난수 생성기는 좋은 균등 분포를 생성합니다. 그들은 단지 무작위가 아닙니다. 문제는 그들이 계산되고 따라서 시퀀스에서 충분한 숫자가 주어진 다음 숫자를 추측 할 수 있다는 것입니다 (이 사실은 진정한 난수가 필요한 보안에 좋지 않습니다). 게임이나 물건에 대해서는 괜찮습니다.
Martin York

5
OP가 C ++ <random> 헤더에 제공된 기능에 대한 특정 정보를 요청하고 있다고 확신합니다. 이 답변은 C ++는 말할 것도없고 프로그래밍도 다루지 않습니다.
Benjamin Lindley

1
@Martin : 보안에 반드시 진정한 난수의 소스가 필요한 것은 아닙니다. 카운터 모드의 AES (예 : 예)는 결정적 임에도 불구하고 매우 훌륭하게 수행 할 수 있습니다. 키에 적절한 양의 엔트로피가 필요하지만 실제 임의성은 필요하지 않습니다.
Jerry Coffin

@ Benjamin Lindley : 신경 쓰지 마세요. 다시 읽고 내가 틀렸다는 것을 깨달았습니다.
N_A
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.