posted by REDFORCE 2017. 3. 23. 08:46

목차


1. Auto

2. range based for

3. enum class

4. non-static data member initializers

5. initializer lists

6. default / delete definition

7. override / final

8. emplacement

9. constexpr

10. lambda

11. random

12. thread


대망의 11편 랜덤 입니다!


11. Random


이번 글은 random에 대해서 정리해보도록 하겠습니다.



과거 C++ 03 까지만 해도


우리는 랜덤한 난수를 쓰기 위해


이런 코드를 작성했었지요...



음...참 그냥 무식한 난수분포기 였습니다.


srand...오랜만에보는군요 = _=)..




먼저 C++03과 C++11의 난수분포기 차이를 비교해보겠습니다.


  C++03 난수분포기

  C++11 난수분포기

 

  • C런타임 난수를 사용

  • 전역 함수 사용

  • 의사 난수 주기가 짧음 ( 최대 32767 )

  • 균등하게 분포되지 않음

  • 기능적으로 빈약함

 

  • 고품질의 난수 생성기와
    분포 클래스를 사용

  • 난수의 형/범위/분포 형태를
    세세하게 조절 가능


사용 방법은 먼저 아래와 같이 간단합니다.




#include <random>에 만들어져있는 std::mt19937 을 이용하는 것인데요.


std::mt19937은 난수 생성기로


Mersenne twister(32비트 버전) 과 std::mt19937_64(64비트 버전) 이 있습니다.



난수를 생성할 때 한번 seed 값을 이용하여 생성해보도록 할까요.





위와 같이 chrono를 이용하여 seed 값을 토대로 난수를 생성할 수 있습니다.


아..혹시나 seed가 뭔말임? 하고 이해 못하시는 분들이 계실까봐.



위쪽에 0 ~100 까지의 난수를 뽑아내기 위해 rand() % 101 을 한 경우가 있지요?


그와 같은 경우라 보시면 될 것 같습니다.

(아니야! 잘못됐어! 라면 지적 해주세요. 사실 저도 정확히 이게 맞나 긴가민가합니다)


[seed 뜻 수정 : 어떤 숫자를 가지고 특정한 수식을 적용 시켜 나온 숫자를 랜덤이라 할 때 필요한 수식에 대입할 숫자를 seed라 부름]



예측 불가능한 난수 생성


혹여나 보안 목적과 같이 절대 예측할 수 없는 난수를 생성하고 싶다면 비 결정적 난수 생성기를 사용해야합니다.


지금 우리가 본 mt19937은 의사 난수라 해서 우리가 일정범위를 지정하고 주관적인 의사가 들어간 난수 입니다.



그럼...예측 불가능한 난수를 어케만드냐?



std::random_device 를 이용하시면 됩니다.


난수 생성을 위해 화면상의 마우스 커서를 이리저리 움직여주세요~ 라는 프로그램같은걸 본적이 있으신가요?


예전에 저는 이런 것을 tortoiseGit 을 사용해 볼 때 난수 생성을 통해 암호알고리즘을 돌리는 것을 본적이 있습니다.



사실 소프트웨어적으로 난수를 생성하는 것은 비결정적 난수를 생성함에 한계가 있습니다.


따라서 이 난수를 하드웨어적으로 움직여서 난수 생성중인 본인도 알기 어려운 (마우스 움직임과 같은) 하드웨어를 이용하는 것이지요.


(난 마우스를 1px 우측으로 움직이고 있어! 라고 미세하게 조정이 가능한 신급 감각을 가진 인물이 라면 가능할지도..)



그래서 다음과 같이 랜덤한 디바이스를 통해 아래 코드 방식대로


비 결정적 난수를 생성 할 수 있습니다.



범위안의 난수 생성

  • 특정 조건 안에 만족하는 난수를 원한다 ( 예 : 1~ 100 사이 )
  • 난수를 특정 타입과 특정 범위 안에서 생성하기 위해서는
    난수 생성기에 난수 분포기를 더하여 난수를 생성한다.
  • 정수 타입의 난수를 분포 할 때는 uniform_int_distribution,
    실수 타입의 난수를 분포 할 때는 uniform_real_distribution 을 사용


위 설명대로 어떤 범위의 난수를 생성 할 떄는 다음과 같이 사용 할 수 있습니다.



차례대로 설명 드리자면 


먼저 난수 생성기! mt19937을 선언하여 rng1(3244) 라고 값을 넣어 아무 숫자나 생성합니다~


그 다음 난수 분포기 uniform_int_distribution 을 이용하여 난수의 분포범위를 결정합니다. ( -3, 3 ) 사이~



해서 난수 분포기 안에 난수 생성기를 넣지요!  // dist1( rng1 )



주의할 점.


std::uniform_intdistribution dist와 std::uniform_real_distribution은 포함 범위가 다르므로 주의!



std::uniform_int_distribution dist( -3, 3 )   // -3 이상,  3까지.


std::uniform_real_distribution<double> dist ( 0.0, 1.0 ) // 0.0 이상, 1.0 미만!



그 외 다양한 난수분포기 들이 있습니다만


대표적으로 사용 되는 녀석들만 적어보도록 하겠습니다.



bernoulli_distribution  분포기

 - 확률을 지정하면 이 확률에 근거하여 true 와 false 를 반환

(예: 몬스터 잡으면 n% 확률로 xx 아이템을 드롭!)


binomial_distribution 난수 분포기

 - 특정 확률로 n 회 실시 했을 때 몇 번 성공 할 것인가를 반환

(예: 사망 가능성(확률)이 있는 백신을 N 사람에게 투여하여 성공할 횟수는?)


normal_distribution 난수 분포기

 - 평균과 표준편차로 정규 분포 난수를 생성한다.

(예: 평균 키 173cm, 표준 편차 5cm 의 신장 데이터를 생성!)



위에 적힌 3가지 외에도 엄청나게 많은 난수 생성기와 분포기가 #include <random> 안에 들어가 있습니다만..


필요한건 그때 그때 찾아서 쓰시거나 직접 로직을 만드시는게 편할거라 봅니다.




결론. 개인적으로 srand() 보단정말 세밀하군요. |(O_ o)/

'Programming > C++' 카테고리의 다른 글

[12편-2] Modern C++ 정리: thread  (0) 2017.03.23
[12편-1] Modern C++ 정리: thread  (0) 2017.03.23
[10편] Modern C++ 정리: lambda  (3) 2017.03.23
[9편] Modern C++ 정리: constexpr  (0) 2017.03.23
[8편] Modern C++정리: emplacement  (0) 2017.03.23