반응형

게임 개발자나 유저들에게 항상 밀접한 관련이 있는 랜덤값에 대해서 알아보자.

 

개발자 입장에서 가장 처음 접하는 랜덤값과 관련된 함수는 아마도 C++의 rand()함수가 아닐까 싶다.

 

msdn의 함수 설명에서는 이렇게 설명하고 있다.

 

rand() 함수는 int 형의 무작위값을 반환하며 error는 반환하지 않는다.

 

더불어 srand()함수를 통해서 rand에 사용할 seed값을 미리 지정해줘야한다

 

다만, rand() 함수는 0 ~ RAND_MAX(32767) 까지의 값만 반환한다고 되어 있다.

 

위 간단하고 굳이 정밀도를 따지지 않는 확률이 요구될 때에는 해당 함수를 사용해도 문제가 생기진 않을것이다.

 

하지만 위 함수를 사용하면 문제가 발생할 수 있는 경우가 많은데 아래의 상황들이다.

 

우선 첫째로는 해당 함수는 의사난수[Pseudo Random] 이기 때문에 동일한 seed값에 대해서는 항상 동일간 결과가 나온다는 점이다.

[ 물론 이 경우 적용하는 곳에 따라 장점이 될 수 있다. ]

 

두번째로는 아래의 예시에 관한 상황이다.

 

우선 내가 원하는 아이템의 id가 70이라고 할 때 0~100000까지의 item들 중 랜덤으로 아이템을 드롭한다고 생각해보자.

 

rand 함수를 사용할때 우선 발생하는 문제는 랜덤값이 32767까지라는 점이다.

 

위의 예를 통해서 본다면 itemid가 32767보다 큰 경우에는 드롭조차 되지 않는다.

 

두번째 문제는 특정 item에 대한 확률이 미묘하게 달라질 수 있다는 것이다.

 

이번에는 itemid가 1~10000까지있다고 가정하고 itemid를 랜덤으로 얻는 방법이 아래와 같다고 생각해보자.

 

itemid = ((rand()+1)%1000 + 1);

 

위 코드의 경우 itemid 는 1~768 / 768 ~ 1000 구간에서의 itemid가 나올 확률이 미묘하게 다르다.

 

A구간[0 ~ 767]과 B구간[768 ~ 999] 구간의 값의 확률 기대값이 다르기 때문이다

 

A구간의 경우 총 33번 나올 수 있다. (ex : 0~767, 1000~767, ...... 32000 ~ 32767)

 

B구간의 경우 총 32번 나올수 있다. (ex :  768 ~ 999, 1768 ~ 1999, ..... 31768 ~ 31999)

 

즉, A구간에 속한 itemId의 경우  미묘하게 드랍될 확률이 높은 것이다.

 

따라서 정밀도, 기대값에 따라 rand()함수의 사용을 잘 고려해야한다.

 

다른 방식의 랜덤값 추출은 어떤게 있을까

 

중앙제곱법, 선형 합동법, XOR-SHIFT 등 여러 방법이 있지만 우선은 메르센 트위스터라는 방법에 대해서 알아보자.

 

메르센 트위스터란?

 

Mersenne-twister [흔히 mt_rand()] 라고 불린다.

 

이 방법은 메르센 소수라는 값을 사용하며 효율이 좋아 C++11 버전에서 mt19937이 표준으로 채택되었다.

 

사용하는 방법도 매우 간단하다.

int main()
{
	auto randSeed;
    std::mt19937 engine(randSeed);
    std::uniform_int_distribution<int> distibution(0, 100);
    auto gen = distribution(engine);
}

위 코드를 보면 우선 하드웨어 리소스를 사용하여 난수를 생성한 후에 0 ~ 100까지 숫자중 임의의 수를 반환한다.

 

난수엔진에 주는 seed값은 필요에 따라 다른값으로 부여하면 된다.

 

이 메르센 트위스터 방식의 경우 기존 rand() 함수보다 랜덤값의 범위가 더 광범위하므로 특정구간에서의 값이 나올 확률차이는 미미하다.

 

기타 다른방식의 랜덤값 추출의 경우 아래의 출처를 읽어보면 좋을것 같다.

https://namu.wiki/w/%EB%82%9C%EC%88%98%EC%83%9D%EC%84%B1

 

난수생성 - 나무위키

Xn+1=(aXn+c) mod mX_{n+1} = (a X_n + c)\ \text{mod}\ mXn+1​=(aXn​+c) mod m static UINT32 next = 1; int __cdecl rand(void) { next = next * 1103515245 + 12345; return (UINT32)(next>>16) & RAND_MAX; } void __cdecl srand(unsigned int seed) { next = seed; } X는

namu.wiki

 

반응형

'기타 상식' 카테고리의 다른 글

프로그램에서 CPU 시간정보 얻는법  (0) 2019.09.20
함수 호출 정보에 관하여  (0) 2019.09.05
FirebaseMessage 란?  (0) 2019.07.31
멀티 스레드에 관해서  (0) 2019.07.14
ORM이란?  (0) 2019.06.23
Posted by Sweetmeats_boy

블로그 이미지
Sweetmeats_boy

태그목록

Yesterday
Today
Total

달력

 « |  » 2024.9
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백

글 보관함