rand 함수로 만든 난수는 진짜로 난수 일까?

평소 써오던 rand 함수에 대해 의문이 생겼습니다.

rand 함수의 동작방식을 이해하고, 정말 난수인지를 확인해 보았습니다.

난수 생성을 위한 함수들

srand, rand, time

srand

rand() 에서 생성되는 난순열의 기준을 초기화 합니다.

  • cstdlib 헤더 안에 있습니다.
  • srand(seed)
    • seed 값에 따라서, 새로운 난순열을 만들어냅니다.
  • 동일한 seed 값이 들어간다면, 매번 같은 난순열을 출력하게 됩니다.
  • 이를 방지하기 위해 time함수를 이용합니다.

time

현재 시간을 구합니다.

  • ctime 헤더안에 있습니다.
  • 현재 시간을 time_t 형식으로 구합니다.
    • 1970-01-01-00시 (UTC) 부터 지금까지 흐른 시간을 로 나타냅니다.
  • time(argument)
    • argument에는 리턴된 시간초를 담고 싶은 time_t 데이터형 변수를 넣으면 됩니다.
    • time 함수자체의 리턴값으로도 시간초를 주기 때문에, 인자를 NULL 로 주며 리턴값을 이용해도 상관없습니다.
1
2
3
    //두 방식은 완전히 동일하게 수행합니다.
    time_t a; time(&a)
    time_t b = time(NULL)
  • time 함수를 이용하여 런타임 도중에 다른 seed 값을 넣어 줄 수 있게됩니다.

rand

난순열를 만들어 냅니다.

  • cstdilb 헤더 안에 있습니다.
  • rand()
    • srand 함수의 seed 값을 기준으로 초기화된 난순열을 만들어내 리턴합니다.

정말 난수일까?

사실 이글을 작성하는 가장 큰 목적입니다.

  • 이전까지 위에 열거한 세개의 함수를 이용해 난수를 만들어 왔습니다.
  • 하지만 이렇게 만들어진 숫자가 정말 난수인가? 라는 의문이 생겼습니다.

결론부터, 난수가 아니다.

위에서 열거한 방법대로 만들어지는 난수는, 의사 난수 입니다.

Seed값은 1초에 한번씩 변한다

현대에는 한 컴퓨터에서 여러 프로그램을 동시에 돌릴 수 있습니다

  • 만약 같은 방식으로 난수를 만들어내는 프로그램이 동시에 돌아가고 있다면?
    • 두 프로그램에서 같은 숫자가 나올것 입니다.
    • 이것이 난수일까요?

rand 의 최대 리턴값이 정해져있다.

한정된 범위의 난수를 만들어 내고 싶을때 문제가 됩니다.

  • 제가 만약 0 ~ 9 사이의 난수를 만들어내고 싶다면 rand() % 10로 만들어 내겠죠.
  • 하지만 rand()의 리턴 최대값이 11 이라면
  • 1 이 나올수 있는 경우의 수는 한개가 더 생깁니다.
  • 모든 수가 등장할 확률이 같지 않습니다.

진짜 난수를 만드려면 어떻게 해야할까?

C++에서는 가능합니다.

  • C++에서는 <random> 라이브러리를 통해 진짜 난수를 제공한다고 합니다.
  • 이 부분에 대한 내용은 체력상의 문제로 나중에 이어 작성하려고 합니다 2020-05-04
  • 지금 당장 궁금하신 분들은 링크 에 가셔서 찾아보셔도 좋겠습니다.

그래도 예제는 있어야 겠죠.

rand()함수를 이용하여 난수를 만들어 봅니다.

  • 코드가 심심하여 quick sort를 구현해 정렬하는 코드를 추가 했습니다.

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <algorithm>
using namespace std;

const int n = 4;
int arr[n];

void Print_arr() {
    for (int it : arr)
        cout << it << " ";
    cout << "\n";
}

void q_sort(int s, int e) {
    if (s >= e) return;

    int mid = s + (e - s) / 2;
    int pivot = arr[mid];

    int left = s - 1, right = e + 1;

    while (1) {
        while (arr[++left] < pivot);
        while (arr[--right] > pivot);

        if (left >= right) break;

        swap(arr[left], arr[right]);
    }

    q_sort(s, left - 1);
    q_sort(right + 1, e);
}



int main()
{
    srand(time(NULL));

    for (int i = 0; i < n; ++i) {
        arr[i] = rand() % 100;
    }

    Print_arr();
    q_sort(0, n - 1);
    Print_arr();

    return 0;
}

결과

1
2
73 62 16 92
16 62 73 92

Reference

  • http://www.cplusplus.com/
  • https://modoocode.com/