물론 내부에서 random()같은 확률함수를 사용하지만, 이 확률함수를 믿을수 있느냐는 문제도 있습니다.
만약 그렇다면 다음과 같은 방식으로 0.1%를 정확하게 만들 수 있습니다.
public class OneByThousent
{
private bool[] array = new bool[1000];
private int point = 0;
public OneByThousent()
{
for(int k = 0; k < 1000; ++k)
array[k] = false;
array[0] = true;
}
}
여기까지 하면 1000개의 배열에 하나의 true가 들어갑니다. 0.1% 확률이죠.
물론 2000개 배열에 true를 2개 넣든가 5000개 배열에 5개를 넣던가 해도 상관 없습니다.
그 다음 이 배열을 잘 섞어줍니다. 이것은 시스템의 random함수를 사용해도 됩니다.
컴파일러마다 조금씩 다르지만, 보통 정수난수를 발생하는 함수라면,
public class OneByThousent
{
private bool[] array = new bool[1000];
private int point = 0;
public OneByThousent()
{
for(int k = 0; k < 1000; ++k)
array[k] = false;
array[0];
Shuffle();
}
private void Shuffle()
{
for(int from = 0; from < 1000; ++from)
{
int to = random() % 1000; // 1)
// from과 to를 맞바꿈
bool tmp = array[from];
array[from] = array[to];
array[to] = tmp;
}
point = 0;
}
}
다음에 이 array에서 하나씩 꺼내옵니다.
public class OneByThousent
{
private bool[] array = new bool[1000];
private int point = 0;
public OneByThousent()
{
for(int k = 0; k < 1000; ++k)
array[k] = false;
array[0];
Shuffle();
}
private void Shuffle()
{
for(int from = 0; from < 1000; ++from)
{
int to = (int)(random() * 1000);
// from과 to를 맞바꿈
bool tmp = array[from];
array[from] = array[to];
array[to] = tmp;
}
point = 0;
}
public bool Get()
{
bool rtn = array[point];
++point;
if(point > 1000)
Shuffle();
return rtn;
}
}
마찬가지로, 만약
public class OneByThousent
{
private float[] array = new float[1000];
private int point = 0;
public OneByThousent()
{
for(int k = 0; k < 1000; ++k)
array[k] = k / 1000F;
array[0];
Shuffle();
}
private void Shuffle()
{
for(int from = 0; from < 1000; ++from)
{
int to = (int)(random() * 1000);
// from과 to를 맞바꿈
float tmp = array[from];
array[from] = array[to];
array[to] = tmp;
}
point = 0;
}
public float Get()
{
float rtn = array[point];
++point;
if(point > 1000)
Shuffle();
return rtn;
}
}
이렇게 하면 0~1 사이에서 1/1000 단위로 균일하게 분포된 난수가 만들어집니다.
다만, 이런 정확한 확률은 shuffle이 여러번 일어날 때 - 컴퓨터가 오랜 시간 돌아갈 때 정확하게 나타납니다.
만약 1/(1백만)의 확률을 만들기 위해 저런 식으로 1백만개의 어레이를 만들었다고 합시다.
그런데 저 함수로 10만개의 확률을 계산한 이후 (점검 등으로) 컴퓨터가 내려가는 일이 반복된다면, 그것은 그냥 random()함수를 사용하는 것이나 다름이 없습니다. 만약 이런 정확한 확률이 필요하다면 이 어레이를 파일이나 DB에라도 저장해 놓고 컴퓨터를 재시작한 이후에도 다시 연결될 수 있도록 해야겠죠.
1) 이런 식으로 나머지연산을 사용하면 일정 범위의 난수를 쉽게 얻을 수 있습니다.
하지만 이럴 경우 주의를 해야 합니다.
언젠가 난수를 출력해 봤는데, 난수가 다음과 같이 나오더군요(물론 이것도 컴파일러에 따라 다릅니다).
random() % 2 : 1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,.......
random() % 4 : 1,3,2,0,1,3,2,0,1,3,2,0,1,3,2,0,1,3,2,0,1,3,2,0,........
random() % 8 : 6,1,7,4,3,0,5,2,6,1,7,4,3,0,5,2,6,1,7,4,3,0,5,2,..........
다른 수일 경우는 괜찮았는데, 저렇게 2의 제곱수의 나머지를 구하면 순서대로 나옵니다.
그러므로 가장 좋은 방법은 다음과 같습니다.
int rnd = (int)((random() * 1000.0) / MAXRANDOM);
ㅇㅋ
답글삭제