2019. 9. 2. 18:58 기타 상식
게임에서의 랜덤값에 대해서
게임 개발자나 유저들에게 항상 밀접한 관련이 있는 랜덤값에 대해서 알아보자.
개발자 입장에서 가장 처음 접하는 랜덤값과 관련된 함수는 아마도 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
'기타 상식' 카테고리의 다른 글
프로그램에서 CPU 시간정보 얻는법 (0) | 2019.09.20 |
---|---|
함수 호출 정보에 관하여 (0) | 2019.09.05 |
FirebaseMessage 란? (0) | 2019.07.31 |
멀티 스레드에 관해서 (0) | 2019.07.14 |
ORM이란? (0) | 2019.06.23 |