난수

난수(亂數)란 정의된 범위 내에서 무작위로 추출된 수를 일컫는다. 난수는 누구라도 그 다음에 나올 값을 확신할 수 없어야 한다.

개요 
컴퓨터 과학 분야에서 말하는 난수는 보통 결정론적인 방법으로 생성된 난수이다. 특정 입력이나 조건에 따라 무작위로 선택된 것처럼 보이는 난수 또는 난수열이 생성되며 그 생성 조건이나 입력이 같다면 그 결과값은 항상 같다. 진정한 의미에서의 난수는 아니지만 그 결과값이 충분히 추측되기 어렵다면 어느정도 난수로서의 의미를 가질 수 있다.

컴퓨터에 의해 생성된 모든 난수는 의사(擬似) 난수이다. 컴퓨터는 계산된 결과만 가지고 난수를 생성할 수 있는데 이 계산된 결과는 입력값에 의해 결정된 값이기 때문에 이 값을 가지고는 난수를 생성할 수 없다. 컴퓨터의 최초 시동시 난수표가 생성되어 컴퓨터내에 보관된다. 하지만 컴퓨터 프로그래밍에서 매번 같은 방법으로 이 값을 가지고 오려고 한다면 매번 그 값은 같기 때문에 최초 한번 호출할 때를 제외하고는 난수라고 볼 수 없다. 그래서 보통 씨앗 값(Seed)이라 불리는 수를 인자로 매번 다르게 주어 매번 다른 의사난수를 추출하여 사용한다. 이 씨앗 값은 보통 시간을 이용한다. 여기서 시간은 보통 현재 시간을 의미한다. 매 순간 현재시간이 바뀌며 한 번 지나간 시간은 다시 돌아오지 않는다는 특성은 이전에 발생했던 의사난수 또는 의사난수열을 재연 불가능하게 만들며, 이 시간이 밀리초 단위로 섬세하게 표현된다면 사람에의한 임의적 조작도 사실상 불가능해진다.

의사 난수 생성 방법 
의사난수를 생성하기 위해서는 변하는 입력(조건)과 함수 두 가지가 필요하다. 함수는 입력값을 이용한 계산을 통해 난수를 생성하는 역할을 하며, 입력값은 매번 다른 난수를 생성하기 위하여 매번 달라져야한다. 이 값을 다르게 하는 방법은 현재 시간을 얻어서 이용하는 방법 또는 이전 결과 값(난수 값)을 다시 입력으로 넣는 방법 등 다양한 방법이 있다.

프로그래밍 언어에서의 의사 난수 발생

C 
먼저 rand() 함수의 원형이 선언되어있는 stdlib.h 헤더파일을 인클루드 한다. 그런 다음 rand() 함수를 호출한다. rand() 함수는 별도로 시드를 설정해주지 않을 경우 동일한 값만을 반복해서 출력하기 때문에 srand() 함수를 이용하여 시드를 설정해준다. srand()의 원형은 void srand(unsigned seed)이기 때문에 시드로 사용할 값을 unsigned형으로 형변환을 하여 넣어준다.#include <stdio.h>
#include <stdlib.h>
#include <time.h>                       //time() 함수의 사용을 위한 헤더파일 인클루드

int main(void)
{
    int random_variable;
    srand((unsigned int)time(NULL));     //시간을 시드값으로 사용
    random_variable = rand()%100;        //0 ~ 99 사이의 난수를 반환
    printf("%d\n", random_variable);
    return 0;
}

C++ 
C++11 표준이 제정되기 이전에는 <cstdlib>을 인클루드 하여 C언어의 rand함수를 그대로 사용하였으나, C++11 표준부터 새로운 방식의 난수생성이 표준으로 제정되어 random 헤더파일을 인클루드 하면 난수를 생성할 수 있다.#include <iostream>
#include <random>

int main(void)
{
    std::random_device generator;                     //하드웨어 리소스에 기반한 난수를 생성
    std::mt19937 engine(generator());                 //난수의 생성방식을 결정. mt19937은 C++11부터 표준으로 제정된 메르센 트위스터 방식의 난수 생성기임 
    std::uniform_int_distribution<int> random(1, 100) //1부터 100까지의 수를 반환, rand%100과는 달리 100도 반환된다.
    std::cout << random(engine) << std::endl;
    return 0;
}

자바 
먼저 java.lang.Math 클래스를 임포트한다.
Math.random()과 같이 사용하면 0에서 1사이의 소수를 얻는다.
보통 (int)(Math.random() * 10)과 같이 형변환을 하여 사용한다.

그 외에도 Random 클래스를 이용하기도 하는데,
Random 클래스 내 nextint(), nextDouble() 등의 메소드를 사용한다.
next 뒤에 오는 Int나 Double은 자료형을 뜻하며 소괄호 안에 숫자를 넣어 난수 범위를 지정할 수 있다.

파이썬 
먼저 import random 구문으로 난수 모듈을 임포트한다.
random.random()과 같이 사용하면 0에서 1사이의 소수를 얻는다. 별도의 범위를 지정해주고자 한다면 randrange()를 이용하여 범위를 지정하여준다.import random

Number = random.random() #0에서 1사이의 소수를 반환
print(Number)

Number = random.randrange(1, 7)   #randrange(a, b)형태로 사용하며 a이상 b미만의 수를 리스트로 생성
print(Number)

Perl 
rand(10) 과같이 쓰면 0에서 10사이의 실수를 반환한다.
보통 int(rand(10))과 같이 사용하여 소수부를 제거하고 사용한다.

각주 

암호학