실제로 어떤 <random>의 난수 엔진을 사용해야합니까? std :: mt19937?


21

<random>실제 프로그램에서 C ++ 기능 을 사용하려고한다고 가정합니다 ( "실제"에 대한 정의 – 여기서 제약은이 질문의 일부 임). 대략 다음과 같은 코드가 있습니다.

int main(int argc, char **argv) {
    int seed = get_user_provided_seed_value(argc, argv);
    if (seed == 0) seed = std::random_device()();
    ENGINE g(seed);  // TODO: proper seeding?
    go_on_and_use(g);
}

내 질문은, 어떤 유형을 사용해야 ENGINE합니까?

  • 나는 std::mt19937타이핑하는 것이 빠르고 이름을 인식했기 때문에 항상 말했었습니다. 그러나 요즘 Mersenne Twister는 매우 무겁고 캐시에 친숙하지 않으며 다른 사람들이하는 모든 통계 테스트를 통과하지 못한다고 말하는 것처럼 보입니다 .

  • std::default_random_engine명백한 "기본"이기 때문에 말하고 싶습니다 . 하지만 플랫폼에 따라 다릅니다 나도 몰라, 그리고 통계적으로 어떤 좋은 모르겠어요.

  • 모든 사람들이 요즘 64 비트 플랫폼이기 때문에, 우리는 적어도 사용되어야합니다 std::mt19937_64이상 std::mt19937?

  • 내가 말하고 싶은 pcg64또는 xoroshiro128그들이 존경하고 가벼운 것 때문에,하지만 그들은 존재하지 않는 <random>전혀.

  • 나는 대해 아무것도 모르는 minstd_rand, minstd_rand0, ranlux24, knuth_b확실히 그들이 뭔가 좋은해야한다 - 등?

분명히 여기에는 경쟁 제약이 ​​있습니다.

  • 엔진의 힘. ( <random>암호 적으로 강력한 PRNG는 없지만 여전히 표준화 된 일부는 다른 것보다 "약한"것입니다.)

  • sizeof 엔진.

  • 그것의 속도 operator().

  • 파종의 용이성. mt19937초기화 할 상태가 너무 많기 때문에 제대로 시드하기 어려운 것으로 악명이 높습니다.

  • 라이브러리 공급 업체 간의 이식성 한 공급 업체가 foo_engine다른 공급 업체와 다른 번호를 생성하는 경우 foo_engine일부 응용 프로그램에는 적합하지 않습니다. (이것은 아마도을 제외하고 아무것도 배제하지 않기를 바랍니다 default_random_engine.)

이러한 모든 제약 조건을 최대한 잘 평가 한 후에 궁극적 인 "표준 라이브러리에 머무는 가장 좋은 방법"은 무엇입니까? 그냥 계속 사용해야합니까 std::mt19937, 아니면 무엇입니까?


2
마지막으로, 모든 표준 엔진 어댑터는 기본 구성된 기본 호출의 특정 연속 호출에서 특정 값을 리턴하도록 지정되므로 이식 가능해야합니다.
1201 프로그램 알람

답변:


15

C ++ 참조 는 현재 C ++에서 제공하는 모든 임의 엔진을 나열합니다. 그러나, 엔진의 선택은 바람직하지 않다 (예를 들어, 고품질 랜덤 제너레이터 목록 참조 ). 예를 들어 :

  • default_random_engine 는 구현에 따라 정의되므로 엔진에 응용 프로그램이 관심을 가질만한 통계적 결함이 있는지 여부를 알 수 없습니다.
  • linear_congruential_engine선형 합동 발생기를 구현합니다. 그러나 모듈러스가 소수이고 매우 크지 않은 경우 (최소 64 비트) 품질이 좋지 않은 경향이 있습니다. 또한 계수보다 더 많은 씨앗을 허용 할 수 없습니다.
  • minstd_rand0그리고 minstd_rand약 2 ^ (31) 씨를 인정한다. knuth_ba를 감싸고 minstd_rand0Bays-Durham이 그것을 섞습니다.
  • mt19937그리고 mt19937_64그들이 더 나은 (예를 들어, 초기화에 의해 초기화된다면 더 많은 씨앗을 인정할 수있는 std::seed_seq다수의 출력을 random_device, 단지 하나), 그러나 그들은 국가의 2500 바이트에 대해 사용합니다.
  • ranlux24ranlux48상태의 577 비트들에 대해 사용되지만 (그들은 일부를 유지하고, 다른 의사 랜덤 출력을 폐기함으로써 작동) 느리다.

그러나 C ++에는 다른 엔진을 래핑하여 무작위 특성을 잠재적으로 향상시키는 두 개의 엔진이 있습니다.

  • discard_block_engine 주어진 랜덤 엔진의 출력 중 일부를 버립니다.
  • shuffle_order_engine 지정된 임의 엔진의 Bays–Durham 셔플을 구현합니다.

예를 들어, 그것의 베이 - 더럼 셔플 가지고, 말, 가능성 mt19937, ranlux24또는 사용자 정의 linear_congruential_engine로를 shuffle_order_engine. 랩핑 된 엔진이 원래 엔진보다 품질이 더 좋을 수 있습니다. 그러나 테스트 하지 않고 새 엔진의 통계 품질을 예측하기는 어렵 습니다 .

따라서 이러한 테스트 mt19937가 진행되는 동안 현재로서는 C ++ 표준에서 가장 실용적인 엔진 인 것 같습니다 . 그러나 향후 C ++ 버전에 다른 난수 엔진을 추가하라는 제안 중 적어도 하나는 알고 있습니다 ( C ++ 용지 P2075 참조 ).


1

에 따르면 C ++ 참조 , default_random_engine:

라이브러리 구현에서 비교적 우연한, 경험이 거나 가벼운 사용을 위해 최소한 수용 가능한 엔진 동작을 제공 하는 생성기 선택입니다 .

그래서위한 경량의 사용 당신은 아무것도에 대한 걱정, 씨앗이 될 필요가 없습니다 default_random_engineEpoch Time (time(0))그 잘 충분하다)


여기서 문제는 이식성이라고 생각합니다. 기본값은 성능이 좋은 엔진 일 수 있지만 다른 플랫폼에서는 재현 할 수 없습니다.
bremen_matt

@bremen_matt 흠 ... 왜 "무작위"숫자를 재현해야합니까?
Farbod Ahmadian

2
테스트. 테스트를 위해 재생 가능한 입력이 필요합니다. 동시에, 입력을 무작위로 원하거나 필요할 수 있습니다. 예를 들어, 대부분의 머신 러닝 알고리즘은 매개 변수가 무작위로 초기화 된 것으로 가정합니다. Ransac, CNN, DNN 등 여러 알고리즘에는 임의의 매개 변수가 필요합니다.
bremen_matt
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.