■ 프로그래밍에서 난수의 이해

 

난수(Random Number)는 시뮬레이션 등의 용도로 프로그래밍에 자주 필요합니다.

 

난수는 많이 발생시킴에 따라 확률을 근사해야 합니다. 예를 들어 주사위 던지기를 모사하기 위해 1~6의 숫자를 난수로 많은 수 얻으면 각 수의 비율이 비슷해야 합니다. 그런데 컴퓨터로 아무 숫자나 계속 만들어 내면 이런 거동을 얻기 어려우므로 말 그대로의 무작위 수는 사용목적에 맞지 않습니다.

 

그래서 의사 난수(pseudo random number)를 사용하는데 이는 정해진 시퀀스에 의해 숫자가 미리 있고 이를 필요에 따라 순서대로 사용하는 것입니다. 이는 확률을 근사하도록 고안되어 있습니다.

 

그런데, 의사 난수(pseudo random number)는 시퀀스가 미리 정해져 있으므로 시작(seed)이 일정하면 항상 일정한 패턴을 얻게 됩니다. 예를 들어 카드를 뒤집을 때 의사 난수에 의해 카드가 정해지게 하면 항상 같은 순서로 카드가 나타나게 됩니다. 이는 또 난수의 의미에 걸맞지 않게 됩니다.

 

이런 문제를 해결하기 위해 매번 시작(seed)을 다르게 합니다. Seed를 무작위로 달라지게 한다면 의사 난수는 진짜 난수처럼 보이게 됩니다. Seed를 정하는 방법은 프로그램이 시작될 때의 시간에 따르게 하는 방법이 흔히 사용됩니다. 프로그램이 시작되는 시간은 자연의 난수임을 활용하는 것입니다.

 

C 프로그램에서는 의사난수를 발생시키기 위해 다음의 함수를 제공합니다. 호출할 때마다 다음 난수가 리턴됩니다. 발생 난수는 Microsoft Visual Studio 환경에서 [0, RAND_MAX]의 범위를 가집니다. RAND_MAX=0x7fff(32767).

 

int rand( void );
 

Seed를 초기화하기 위해서는 다음의 초기화 함수를 호출해야 합니다.

 

void srand( unsigned int seed );

 

보통 시간을 seed로 초기화하기 위해 다음과 같이 호출됩니다. 보통 프로그램 시작될 때 한번 호출합니다.

 

srand( (unsigned)time( NULL ) );

 

■ 범위 내의 난수 발생 방법

 

원하는 범위 내에 있는 난수를 얻을 필요가 흔히 발생합니다. 난수 발생 함수는 정해진 범위의 수를 돌려주므로 이를 적절히 스케일링 할 필요가 있습니다.  다음 프로그램의 RangedRandomNumber() 함수는 이의 예를 보여줍니다. 필요할 때  긁어서 사용하면 되겠습니다.

 

 


#include <stdio.h>
#include <time.h>  //time()
#include <stdlib.h>  // RAND_MAX=0x7fff(32767)


//=============================================================================
// 반개구간 [range_min, range_max) 의 난수를 리턴
// 즉, range_min <= random number < range_max
//=============================================================================
int RangedRandomNumber( int range_min, int range_max )
{
    int u = (int)((double)rand() / (RAND_MAX + 1) * (range_max - range_min) + range_min);
    return u;
}


//=============================================================================
// main() 함수
//=============================================================================
int main( void )
{
    int i, nrandom;

 

    // 난수 발생기의 seed는 현재 시각으로 하여 매번 다르게 한다.
    srand( (unsigned)time( NULL ) );

 

    // 폐구간 [0, RAND_MAX] 의 10개 난수 출력
    for( i = 0; i < 10; i++ )
    {
        nrandom = rand();
        printf( "  %6d\n", nrandom );
    }
    printf("\n");

 

    // 반개구간 [-100, 100) 의 10개 난수 출력
    for( i = 0; i < 10; i++ )
    {
        nrandom = RangedRandomNumber(-100, 100);
        printf( "  %6d\n", nrandom );
    }
}


 

Posted by 마스샘