본문 바로가기
Dev Note/else

컴퓨터에서 생성하는 난수는 진짜 난수가 아니다?

by iyos 2020. 10. 22.

 

코드를 짜다보면 '난수'를 사용해야하는 경우가 많다.

습관적으로 Random클래스나 Math클래스의 random() 매소드를 쓰곤 했는데 정확한 차이를 모르고 썼는데,

알고리즘 공부를 하던 중 난수가 진짜 난수가 아니라는 글을 보고 이참에 컴퓨터가 난수를 생성하는 과정을 정확히 알고싶어졌다.

 

 


 

난수란?

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

 

 

하지만 컴퓨터 과학 분야에서 말하는 난수는 보통 결정론적인 방법으로 생성된 난수이다.

특정 입력이나 조건에 따라 무작위로 선택된 것처럼 보이는 난수 또는 난수열이 생성되며 그 생성 조건이나 입력이 같다면 그 결과값은 항상 같다. 진정한 의미에서의 난수는 아니지만 그 결과값이 충분히 추측되기 어렵다면 어느정도 난수로서의 의미를 가질 수 있다. 즉, 프로그래밍에서 난수란 시스템적으로 임의의 수를 만들어 적용하는 기준을 말한다. 

 

 

의사난수란?

의사 난수, 擬似(본뜰 의, 비슷할 사)亂數, Pseudo-Random Number, PRN.

컴퓨터에 의해 생성된 모든 난수는 의사난수이다. 생각 외로 컴퓨터는난수를 간단히 만들 수 없다. 컴퓨터는 기본적으로 정해진 입력에 따라 정해진 값을 낼 뿐이다. 사람처럼 무의식적인 선택, 혹은 우연에 의한 선택을 할 수 없기 때문이다. 흔히 보는 랜덤은 정말로 임의의 값이 아니고 특정한 방법으로 계산하거나 몇 밀리초(ms) 단위로 시시각각 변하는 값을 초기값으로 잡은 다음 여러 계산 과정을 거쳐 사람이 볼 때에는 마치 임의의 값인 것처럼 보이게하는 것이다. 이것을 의사난수라고 한다.

 

 

흔히 난수표를 쓰는데 난수표가 정해진 이상 결국 같은 순서로 같은 숫자가 나오게 된다.

이를 해결하기 위한 방법은 난수표를 여러개 만들어 놓고 매번 다른 난수표를 읽도록 만드는 것이다. 그래서 보통 씨앗 값(Seed)이라 불리는 수를 인자로 매번 다르게 주어 매번 다른 의사난수를 추출하여 사용한다. 이 씨앗 값은 보통 시간을 이용한다. 여기서 시간은 보통 현재 시간을 의미한다. 매 순간 현재시간이 바뀌며 한 번 지나간 시간은 다시 돌아오지 않는다는 특성은 이전에 발생했던 의사난수 또는 의사난수열을 재연 불가능하게 만들며, 일반적으론 밀리초, 즉 1/1000초 단위의 값이니 인간이 의도적으로 같은 값을 내게 하는건 불가능에 가깝다.

 

 

Seed로 사용되는 것들은 현재 시간 외에도 다양하다.

Windows에선시간 이외에도 컴퓨터가 켜져있는 시간 (ns단위), CPU 메모리의 클럭/온도, 프로세스 ID나 쓰레드 ID (매 부팅마다 방 온도나 발전소 전기 품질, 컴퓨터 내부 부품 등에 따라 어느정도씩 전부 달라질 수 있는 것 들이다.) 등도 사용한다. 마지막으로 생성한 난수값을 별도로 저장해 뒀다가 그것을 시드로 하기도 하고 사용자의 입력 행동 자체를 시드로 하기도 한다. 사용자의 마우스 움직임이나 키보드의 키를 누른 시간 간격 등을 샘플링해서 그것을 시드값으로 삼기도 한다. 이와 같이컴퓨터가 진짜 랜덤값을 얻을 수 있는 방법이 수도 없이 많다.

 

 

그래서 완전 무작위라고 볼 수 있는가?

여러 개선책이 있지만 근본적으로 시드를 기반으로 한 랜덤함수는 완전한 무작위라고 보기가 힘들다. 특정 패턴의 경우 영원히 안 나올 수도 있다. 암호화에도 문제가 되는데, 시드 기반 난수로 암호화 키를 생성하는 경우 키 값의 일부를 알고 있다면 나머지 키 값도 유추하는게 가능해질 수 있다. 일반적인 게임에서는 어느정도의 무작위성으로도 충분하지만, 현찰이 오가는 도박 사이트처럼 정말 랜덤이 필요한 경우 시드 기반의 의사랜덤은 쓰지 않는다.

 

 

'적당한 무작위성'이 장점으로 활용되는 경우도 있다.

의사난수의 '같은 시드는 같은 결과를 부른다'를 장점으로 활용해, 네트워크 게임의 플레이어 간 동기화에서부터 리플레이 모드 구현까지 많은 곳에 써먹을 수 있다. 마찬가지로 도박에서 원하는 결과가 나오게 악용할 수 있다. 이런 걸 난수조절이라고 한다. 게임에서는 상황에 따라 어떤 커맨드를 입력하거나 할 때 그 결과가 무작위적으로 나오거나 특정한 확률 내에서 이벤트가 발생하도록 해야 할 때가 있다.  다만, 일반적인 플레이에서는 이를 일일이 생각하면서 조작하는 사람이 없기 때문에 실질적으로 난수가 될 수 있는 것이다. 

 

 

 

참고:

ko.wikipedia.org/wiki/%EB%82%9C%EC%88%98 

 

난수 - 위키백과, 우리 모두의 백과사전

위키백과, 우리 모두의 백과사전. 난수(亂數)란 정의된 범위 내에서 무작위로 추출된 수를 일컫는다. 난수는 누구라도 그 다음에 나올 값을 확신할 수 없어야 한다. 컴퓨터 과학 분야에서 말하는

ko.wikipedia.org

namu.wiki/w/%EB%82%9C%EC%88%98%EC%83%9D%EC%84%B1

 

난수생성 - 나무위키

Xn+1=(aXn+c) mod mX_{n+1} = (a X_n + c)\ \text{mod}\ mXn+1​=(aXn​+c) mod m static UINT32 next = 1; int __cdecl rand(void) { next = next * 1103515245 + 12345; return (UINT32)(next>>16) & RAND_MAX; } void __cdecl srand(unsigned int seed) { next = see

namu.wiki

 

반응형