79 lines
2.3 KiB
C++
79 lines
2.3 KiB
C++
#pragma once
|
|
|
|
#include <algorithm>
|
|
#include <cstdlib>
|
|
#include <cassert>
|
|
#include <cmath>
|
|
|
|
|
|
// Mersenne Twister
|
|
extern void XInitRandom( unsigned seed );
|
|
extern int XRandom();
|
|
inline int XRandom( int min, int max )
|
|
{
|
|
if ( min == max ) return min;
|
|
|
|
assert( min < max );
|
|
if( min > max )
|
|
{
|
|
std::swap( min, max );
|
|
}
|
|
|
|
return ( XRandom()%(max-min+1) + min );
|
|
}
|
|
|
|
// Error function 위키페이지의 Section 2.2 Inverse functions에서 Approximation with elementary functions 방법 이용
|
|
// http://en.wikipedia.org/wiki/Error_function
|
|
inline double XInverseErf( double x )
|
|
{
|
|
// 상수들
|
|
const double XRAMDOM_PI = 3.14159265358979; // 원주율
|
|
const double XRAMDOM_squareTwo = 1.4142135623731; // 루트 2
|
|
const double XRAMDOM_ALPHA = 0.140012; // a 상수 (erf inv 근사식에 사용)
|
|
|
|
if( x >= 1 || x <= 0 )
|
|
return RAND_MAX;
|
|
|
|
double z = 2*x - 1;
|
|
double fConst = 2/XRAMDOM_PI/XRAMDOM_ALPHA; // 계산을 위한 상수
|
|
double fVar = log( 1 - z*z ) / 2; // 계산을 위한 변수
|
|
|
|
if( z > 0)
|
|
return XRAMDOM_squareTwo * sqrt( sqrt( ( fConst + fVar )*( fConst+ fVar ) - fVar * 2 / XRAMDOM_ALPHA ) - ( fConst+ fVar ) );
|
|
else
|
|
return -XRAMDOM_squareTwo * sqrt( sqrt( ( fConst + fVar )*( fConst+ fVar ) - fVar * 2 / XRAMDOM_ALPHA ) - ( fConst+ fVar ) );
|
|
}
|
|
|
|
// 극값이 나올 확률을 extreme으로 정한다.
|
|
// 예) 1%의 확률로 최상옵이 뽑히게 하고싶다 -> extreme = 0.99
|
|
// 자동으로 1%확률로 최하옵도 뽑히게 된다.
|
|
// maxValue는 extreme의 확률로 일어나는 사건의 한계값을 설정한다.
|
|
// 만약 이 확률이 일어날 확률보다 낮은 사건이 일어낫을 경우에는 최대/최소를 넘으므로 다시 랜덤을 돌린다.
|
|
inline int XNormalRandom( int min, int max, double extreme )
|
|
{
|
|
if ( min == max ) return min;
|
|
|
|
double maxValue = XInverseErf( extreme );
|
|
|
|
double dResult;
|
|
do
|
|
{
|
|
int nRand = XRandom( 1, RAND_MAX-1 );
|
|
double dProb = ( double )nRand/RAND_MAX; // 확률 p (0,1)
|
|
dResult = ( min + max )/2.0 + ( XInverseErf( dProb ) / maxValue / 2 ) * ( max-min );
|
|
}
|
|
while( dResult > max || dResult < min );
|
|
|
|
return static_cast< int >( dResult + 0.5 ); // 0.5는 반올림을 위함.
|
|
}
|
|
|
|
inline int XFastRandom()
|
|
{
|
|
return XRandom();
|
|
}
|
|
|
|
inline int XFastRandom( int min, int max )
|
|
{
|
|
return XRandom( min, max );
|
|
}
|