본문 바로가기

Game Programming

Mersenne-Twister 난수 발생기

728x90
반응형
게임 코딩 컴플릿책에서 보고 좋은 랜덤함수 추출기란다. rand보다 좋은거 ㅋㅋ
잘 써먹자 ㅋㅋ

//Mersenne-Twister 난수 발생기
//주기 매개변수들
#define CMATH_N 624
#define CMATH_M 397
#define CMATH_MATRIX_A 0x9908b0df //상수 벡터 a
#define CMATH_UPPER_MASK 0x80000000 //최상위 w-r비트들
#define CMATH_LOWER_MASK 0x7fffffff //최하위 r 비트들
//조절용 매개변수들
#define CMATH_TEMPERING_MASK_B 0x9d2c5680
#define CMATH_TEMPERING_MASK_C 0xefc60000
#define CMATH_TEMPERING_SHIFT_U (y) (y >> 11)
#define CMATH_TEMPERING_SHIFT_S (y) (y << 7)
#define CMATH_TEMPERING_SHIFT_T (y) (y << 15)
#define CMATH_TEMPERING_SHIFT_L (y) (y >> 18)
class CRandom
{
//데이터
unsigned int rseed;
unsigned long mt[CMATH_N]; //상태 벡터를 위한 배열
int mti; //mti==N+1은 mt[N]이 초기화되지 않았음을 뜻한다.

public:
CRandom(void);
unsigned int Random(unsigned int n);
void SetRandomSeed(unsigned int n);
unsigned int GetRandomSeed(void);
void Randomize(void);
};
CRandom::CRandom(void)
{
rseed = 1;
mti = CMATH_N+1;
}
//0에서 n사이의 (n은 제외) 한 난수를 돌려준다.
unsigned int CRandom::Random(unsigned int n)
{
unsigned long y;
static unsigned long mag01[2] = {0x0, CMATH_MATRIX_A};
if(n==0)
return(0);
//x가 0이나 1이면 mag01[x] = x * MATRIX_A
if(mti >= CMATH_N) //한번에 N개의 워드를 생성
{
int kk;
if(mti == CMATH_N+1) //sgenrand()가 호출된적이 없다면,
SetRandomSeed(4357); //기본초기 종자값을 사용한다.
for(kk=0;kk{
y = (mt[kk]&CMATH_UPPER_mASK) | (mt[kk+1]&CMATH_LOWER_MASK);
mt[kk] = mt[kk+CMATH_M] ^ (y>>1) ^ mag01[y & 0x1];
}
for(;kk{
y = mt[kk]&CMATH_UPPER_MASK)|(mt[kk+1]&CMATH_LOWER_MASK);
mt[kk] = mt[kk+(CMATH_M-CMATH-N)] ^ (y >> 1) ^ mag01[ y & 0x1];
}
y = (mt[CMATH_N-1]&CMATH_UPPER_MASK)|(mt[0]&CMATH_LOWER_MASK);
mt[CMATH_N-1] = mt[CMATH_M-1] ^ (y >> 1) ^ mag01[y & 0x1];
mti = 0;
}
y = mt[mti++];
y ^= CMATH_TEMPERING_SHIFT_U (y);
y ^= CMATH_TEMPERING_SHIFT_S (y) & CMATH_TEMPERING_MASK_B;
y ^= CMATH_TEMPERING_SHIFT_T (y) & CMATH_TEMPERING_MASK_C;
y ^= CMATH_TEMPERING_SHIFT_L (y);
return (y%n);
}
void CRandom::SetRandomSeed(unsigned int n)
{

//초기종자값들을 mt[N]에 설정한다.
mt[0] = n & 0xffffffff;
for(mti=1;mtimt[mti] = (69069 * mt[mti-1]) & 0xffffffff;
rseed = n;
}
unsigned int CRandom::GetRandomSeed(void)
{
return(rseed);
}
void CRandom::Randomize(void)
{
SetRandomSeed(time(NULL));
}
//구현부분
CRandom r;
r.Randomize();
unsigned int num = r.Random(100); //0에서 99사이의 난수를 얻는다.
728x90
반응형