Programming/C language

srand 마이크로 시간대로 뽑아내기

choimosi 2010. 10. 1. 01:46
본 글은 퍼온 글입니다. 아래 소스는 리눅스에서만 작동하니 그 점을 숙지해야 합니다.
srand(time())가 1초마다 값이 바뀌다 보니 랜덤 값이 항상 일정한데  그 점을 보안하기 위한 함수 입니다.
아래 글은 퍼온 글이고 윈도우 모드에서 랜덤값을 주는 방법은 더 아래에 있습니다.

요즘 동아리에서 C 스터디를 하고 있습니다. 리눅스 프로그래밍, 윈도우즈 프로그래밍, 루트킷 탐지 프로그램 프로젝트를 하기 위한 선행학습이지요. 복습도 되구요.

우선, 로또 게임 시뮬레이션을 만들었는데, 주석을 포함하여 217줄이 나오더군요. 그 코드 중에서 번호를 무작위로 섞는 함수 부분에 대해 얘기하고자 합니다. 자, 그러면 코드부터 볼까요?

/* ===  FUNCTION  ===========================================================
 *         Name:  Shuffle_numbers  *  Description:  45개의 번호를 무작위로 섞습니다.  * ======================================================================== */

void Shuffle_numbers (int numbers[]) {
   
int temp = 0;     int i, j;     srand(time(NULL));     for (i = 0; i < 45; i++)     {         j = rand() % 45;         temp = numbers[i];         numbers[i] = numbers[j];         numbers[j] = temp;     } }
배열에 저장된 45개의 번호를 무작위로 서로 맞바꾸는 알고리즘입니다. 알고리즘 자체는 쉽죠? Swap 알고리즘은 워낙 많이 쓰이는거니까 다들 잘 아실테구요. 아! 예전의 글을 기억하시나요? "알고리즘 :: XOR 연산을 이용하여 스왑 알고리즘을 최적화하자." 사실은 최적화 기법이 아니었지만, 저런 방법도 있다는 것만 아시면 됩니다.

이제 프로그램을 한 번 돌려보겠습니다.

사용자 삽입 이미지

어? 와! 전부 1등에 당첨되었습니다. 이거 로또 질러야겠네요? 라고 생각하면 큰일이죠. 각 게임의 번호가 모두 똑같이 나왔습니다. 왜 이런 걸까요? 흠... 제목에서 이미 유추하신 분도 계실 듯 한데요.

예, 이유는 srand(time(null))에 있습니다. rand() 함수를 목적대로 사용하려면 srand() 함수로 패턴을 바꿔줘야 합니다. 그리고 time(null)을 seed로 줘서 이러한 패턴을 매번 다르게 만들어야 한다는 것은 잘 아시죠?

문제는 time() 함수가 초 단위를 생성한다는 데 있습니다. 즉, seed가 초 단위로 바뀐다는 얘기이죠. 느린 컴퓨터에서야 문제가 없겠지만, 빠른 컴퓨터에서는 1초 안에 수많은 작업을 할 수 있기 때문에 위에서 1초 동안 모든 작업이 이루어진 것입니다. seed가 똑같으니 아무리 rand() 함수를 사용한다해도 같은 번호가 나올 수 밖에요. srand() 함수를 안 쓴거나 마찬가지이죠.

그래서 아래와 같이 고쳤습니다.

/* ===  FUNCTION  ===========================================================
 *         Name:  Shuffle_numbers
 *  Description:  45개의 번호를 무작위로 섞습니다.
 * ======================================================================== */
void Shuffle_numbers (int numbers[]) {  int temp = 0;
 
int i, j;
  srand
(time(NULL));
 
for (i = 0; i < 45; i++)
 
{
        j
= rand() % 45;
        temp
= numbers[i];
        numbers
[i] = numbers[j];
        numbers
[j] = temp;
       
/*----------------------------------------------------------------------------------------------------------------------------------------------------------
         *  srand(time(NULL))은 초 단위로 seed를 생성하므로 usleep()으로 대기합니다.
         *  대기하지 않는다면, 매우 빠른 속도로 rand()가 실행되어 같은 값이 출력됩니다.
         *---------------------------------------------------------------------------------------------------------------------------------------------------------*/

        usleep
(25000);
   
}
}
주석에 나와 있듯이, 인위적으로 seed가 바뀌는 틈을 주었습니다. usleep() 함수는 마이크로 초 단위를 생성합니다. 그러니 위 코드에서는 25000 마이크로 초 이겠죠? 저보다 빠르면 간혹 같은 결과가 나타나고, 느리면 프로그램의 진행에 방해가 되서 저 정도가 딱인 것 같습니다.

아무튼, 이런 것도 일일이 지정해줘야 할만큼 컴퓨터는 바보인 겝니다. 뭐, 어쩔 수 없죠. 이제 다시 결과를 확인 해볼까요?

사용자 삽입 이미지

이제서야 원하던(?) 결과를 얻었습니다. 1등이 없네요? 원치 않던 원하던 결과...? 아무튼 그렇습니다. (1000 게임을 시뮬레이션해봤더니 가장 높게 나온 것이 4등이었습니다. 뭐, 그런 겝니다. 로또란...)

참고 문헌

조인시 위키: usleep(3) :: http://www.joinc.co ··· 3%2Fusleep
alarm 과 sleep 그리고 usleep :: http://kicom95.egloos.com/682919
rand() 함수에 대해서... :: http://blog.niu.kr/21

원본: http://hisjournal.net/blog/214



윈도우 이용 시 무한 랜덤 값 획득 방법은
#include<windows.h>   //GetTickCount(), Sleep(microsecond)

srand(GetTickCount());  윈도우 함수에 있는 GetTickCount 함수를 사용하는 방법이 있습니다.
하지만 컴퓨터가 빠르면 스케쥴링의 상황에 따라 또 랜덤 값이 변하는 경우가 있습니다.
이때를 위해
windows.h를 부르면 포함되는 Sleep(20) 함수를 이용해서 적당히 딜레이 값을 조정해주면
지속적인 랜덤값을 생성할 수 있습니다.