WELL512 난수 발생 알고리즘 - C#
랜덤 함수에 대한 재미있는 글이 있어서 소개합니다. ^^ (스타 크래프트등의 게임에서 random seed 값을 일치시켜서 서로 다른 클라이언트들끼리의 동기화를 했다는 아이디어도 재미있습니다. ^^)
표준 rand() 함수보다 유용한 랜덤 생성 알고리즘 - MT, WELL
; http://www.gamedevforever.com/114
이런 건 널리 퍼뜨려야 한다고 생각하는 차원에서 위에서 소개된 WELL512의 C# 버전도 간단하게 포팅해 보았습니다. (이미 위의 글을 쓰신 분이 C++로 잘 포팅해 주셔서 뭐 별로 할 건 없었습니다. ^^)
public class Well512
{
static uint[] state = new uint[16];
static uint index = 0;
static Well512()
{
Random random = new Random((int)DateTime.Now.Ticks);
for (int i = 0; i < 16; i++)
{
state[i] = (uint)random.Next();
}
}
internal static uint Next(int minValue, int maxValue)
{
return (uint)((Next() % (maxValue - minValue)) + minValue);
}
public static uint Next(uint maxValue)
{
return Next() % maxValue;
}
public static uint Next()
{
uint a, b, c, d;
a = state[index];
c = state[(index + 13) & 15];
b = a ^ c ^ (a << 16) ^ (c << 15);
c = state[(index + 9) & 15];
c ^= (c >> 11);
a = state[index] = b ^ c;
d = a ^ ((a << 5) & 0xda442d24U);
index = (index + 15) & 15;
a = state[index];
state[index] = a ^ b ^ d ^ (a << 2) ^ (b << 18) ^ (c << 28);
return state[index];
}
}
위에서는 초기 state 배열을 Random으로 초기화 시키고 있지만, 원래는 랜덤값에 대한 일치를 목적으로 사용하는 것이기 때문에 개발자가 임의로 넣어주어야 합니다.
아래는 간단하게 Random과 Well512의 난수 비교를 한 것입니다.
static void Main(string[] args)
{
Random random = new Random((int)DateTime.Now.Ticks);
for (int i = 0; i < 10; i++)
{
int rand1 = random.Next();
ulong rand2 = Well512.Next();
Console.WriteLine(i + ": " + rand1 + ", " + rand2);
}
Console.WriteLine();
for (int i = 0; i < 10; i++)
{
int rand1 = random.Next(10);
ulong rand2 = Well512.Next(10);
Console.WriteLine(i + ": " + rand1 + ", " + rand2);
}
Console.WriteLine();
for (int i = 0; i < 10; i++)
{
int rand1 = random.Next(5, 15);
ulong rand2 = Well512.Next(5, 15);
Console.WriteLine(i + ": " + rand1 + ", " + rand2);
}
// perf
// Random
PerfOfRandom(random, 10);
PerfOfMT(10);
PerfOfRandom(random, 100000000);
PerfOfMT(100000000);
}
출력 결과는 다음과 같습니다.
0: 1730630173, 3099563570
1: 817418037, 2432892948
2: 834912966, 646458163
3: 637659925, 3393587455
4: 789744846, 1702337066
5: 1836434216, 82224553
6: 747279096, 1371995332
7: 681895050, 3383000384
8: 1976598118, 2439882382
9: 520252988, 4048663526
0: 6, 3
1: 1, 5
2: 9, 1
3: 8, 6
4: 5, 9
5: 1, 7
6: 2, 8
7: 9, 2
8: 4, 1
9: 7, 7
0: 10, 9
1: 14, 14
2: 8, 12
3: 12, 11
4: 13, 13
5: 12, 14
6: 5, 7
7: 12, 12
8: 14, 11
9: 12, 5
10 elapsed: 0 // JIT 컴파일 고려
10 elapsed: 0 // JIT 컴파일 고려
100000000 elapsed: 1747 - System.Random
100000000 elapsed: 2897 - Well512
Random과 비교한 성능이 의외군요. 물론 루프 횟수가 워낙 크기 때문에 저 정도의 성능 차이는 무시할 수 있을 정도라고 여겨집니다. 사실, 결과적으로 보면 Well512 클래스 자체가 닷넷에서는 크게 의미가 없어 보입니다. 왜냐하면, C++의 rand() 함수가 전역적인 반면 닷넷의 System.Random 타입은 인스턴스가 지역적으로 관리될 수 있기 때문에 두 기기 간의 동기화를 맞추는 데 전혀 문제가 없습니다.
그렇지만, 굳이 활용도를 생각해 본다면 서로 다른 언어간의 동기화를 맞출 일이 있는 경우겠지요. WELL 소스 코드가 간단하기 때문에 자바로도 포팅이 가능하기 때문입니다.
(
첨부된 파일은 위의 코드를 포함한 예제 프로젝트입니다.)
그나저나... 게임 개발자들로부터 배울 것들이 정말 많군요. 지난번 글도 그렇고. ^^ 요즘 들어서 그들의 열정과 지식에 대한 탐구에 놀라게 됩니다.
홀 펀칭(Hole Punching)을 이용한 Private IP 간 통신 - C#
; https://www.sysnet.pe.kr/2/0/1226
[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]