RANDOMU 함수의 알고리즘 변경 (8.2버전 이후)

RandomU 함수에서 Seed 값을 상수로 지정할 경우, 항상 같은 값이 나옵니다.

원하는 것이 매회 다른 무작위 수를 발생하는 것이라면, 이렇게 작성하면 안됩니다. 이렇게 상수로 지정하는 이유는, 주로 교육적인 목적에서, 또는 어떤 특별한 이유로 “재현”을 하기 위한 조치입니다. 난수 생성의 본래의 목적인 매번 다른 무작위 수를 생성하고자 한다면, SEED 값을 변수로 지정해야 합니다. 이 변수를, 해당 IDL 세션에서 처음 사용하는 변수로 지정한다면, IDL이 시작된  시각(Time of Day) 정보를 초기값 설정에 사용함으로써, 매 프로그램 실행시 마다 다른 값을 만들어 내게 됩니다.

복잡할 것 없습니다. 대부분의 과학자들이 이렇게 씁니다.

그냥 보기도 좋기 위해서 다들 사용하는 변수 이름이 seed 입니다. 아마도 위의 값은 여러분들 컴퓨터에서 재현하기가 아주 어려울 것입니다. 사실 이것이 RANDOM 이라는 의미겠지요. 그리고 실행할 때마다, seed 변수에는 괴상한 값들이 잔뜩 들어가는데, 그 내용은 RandomU를 구현한 알고리즘에 달린 것이고, 우리는 그 내용을 알 필요가 없습니다. (print, seed를 해 보세요. 알고 싶지 않으실 겁니다).

그렇지만 어쨌든, ‘교재와 교재를 따라하는 실습자가 같은 결과를 내며 진행하기 위해’ seed 값을 고정값으로 하는 것은 가끔 있는 일입니다. 이 때, RandomU는 무작위수를 발생하는 것이 목적이라기 보다는, 어떤 실습용 데이터를 간편하게 생성하고자 사용되는 거예요. 예를 들면 David Fanning 박사님의 다음 글은 처음 실습 데이터를 RandomU로 만들고 있습니다.

D. Fanning 박사님의 글에서 사용된 RandomU 사용예 (idlcoyote.com/graphics_tips/histoplot.php)

David Fanning 박사님의 위 글은 Histogram 을 잘 그리는 방법을 설명하는 것이 목적인데, Histogram을 시도해 볼 데이터 생성에 RandomU를 사용하고 있습니다. 아마도, 실습으로 따라서 해보는 분들이 똑같은 그림을 만들 수 있도록 일부러, RandomU(5L, 200) 과 같이 Seed 값을 5L 이라는 상수로 사용했다고 생각합니다.

그런데, 이 내용을 지금 IDL에서 따라 해보면, 그림이 다르게 보입니다. 이런…

D. Fanning 박사님의 그림과 다릅니다. 이건 좀 이상한 일이죠.

Seed 값으로 상수를 쓰면 계속 같은 값의 수열을 출력하는 것은 여전히 유효합니다. 아마도 여러분이 위 두 문장을 따라해 보신다면, 제가 그린 그림과 “같은” 결과가 나올 것입니다. “재현”이 되고 있는 거죠. 다만, D. Fanning 박사님의 그림과는 다릅니다. 혹시 현재 IDL 8.1 또는 그 이전 버전을 사용하신다면 반대로, D. Fanning 박사님의 그림과 같은 결과가 나올 것입니다. 그렇습니다. 이 문제는 IDL 8.1 이전 버전과 이후 버전의 차이에 원인이 있습니다.

IDL 8.2.2 부터 IDL의 기본 난수발생 알고리즘이 바뀌었습니다. 이 부분에 대한 자세한 내용이 필요하시면 도움말을 참고하십시오. 저는 사실 새 알고리즘이 얼마나 대단한 발전을 이룬 것인지 잘 모릅니다. IDL 최신버전에서 RandomU 함수를 사용하신다면, Mersenne Twister 알고리즘을 사용한 난수를 발생하고, 이는 (2^19937) – 1 개 라는 큰 순환주기를 가진다고 해서 MT19937 알고리즘이라고 불리기도 한다는군요.

그리고, 이제서야 다시 들여다 보게 되는 건데, IDL 8.1 이하 버전의 난수 발생 알고리즘은 RAN1 이라는 Numerical Recipes in C 에 나오는 알고리즘이라고 합니다. 사실 예전 IDL의 많은 수치해석용 라이브러리가 Numerical Recipes in C를 근거로 하고 있었습니다. Numerical Recipes in C가 수치해석의 교과서로는 가장 유명하지만, 시간이 많이 흘러 이 책에 소개된 알고리즘들은 조금 낡은 방식으로 여겨지기도 합니다. 그래서 IDL에서는 꾸준히 새로운 수학 라이브러리들을 추가로 적재하고 있는데, 선형대수 라이브러리 LAPACK 이라든지, 상용 라이브러리인 IMSL 같은 것이 IDL에서 이미 사용되고 있습니다. RAN1 알고리즘이 난수의 가장 절실한 사용 분야인 Monte Carlo 실험 등에 적합하지 않다는 의견을 들어본 적도 있습니다. 그래서 조금 더 현대적인 난수 발생 알고리즘으로 아예 바꾸게 된 것 같습니다.

“아… 그렇더라도 책에 나오는 것과 똑같은 결과를 보고 싶어요.”

위와 같은 요청이 있다면, 책은 IDL 8.1 이전 버전에서 씌여진 것이고, 여러분의 IDL이  8.2.2 이후 버전이라면, /RAN1 키워드를 사용하면 됩니다. 도움말에 의하면 /RAN1 키워드는 오직 과거와의 호환을 위해서만 존재할 뿐, 웬만하면 지금의 디폴트 알고리즘을 쓰는 게 좋다고 하는군요.

/RAN1 키워드로 D. Fanning 박사님의 그림과 같은 결과를 만들 수 있습니다.

정리하겠습니다.

  • RandomU(5L, 10) 과 같이 Seed 값을 상수로 사용하는 이유는 재현 시 똑같은 결과를 보기 위함입니다. 주로 교육적인 목적으로 사용됩니다.
  • 정말로 매번 바뀌는 무작위수를 만들고자 할 때는 RandonU(seed, 10) 과 같이 앞에 사용된 적 없는 변수를 Seed 값으로 배정합니다.
  • Seed 값을 상수로 주었음에도, 예전에 작성된 문서들과 다른 결과를 보게 될 수 있습니다. 이는 IDL 8.2.2 부터 RandomU의 디폴트 알고리즘이 RAN1 에서 Mersenne Twister 로 바뀌었기 때문입니다.
  • Mersenne Twister 알고리즘이 더 좋은 알고리즘입니다. 다만, 과거 버전에서와 똑같은 결과를 얻는 것이  꼭 필요한 경우를 위해 /RAN1 키워드를 제공합니다.
  • 과거 버전과 똑같은 결과를 얻는 것이 필요하지 않다면(대부분의 실전 상황에서), 예전에 만든 프로그램을 단 한 글자도 고칠 필요가 없습니다.

참고

IDL의 무작위수 발생 함수 RandomU (Uniform 을 의미합니다. 생성 범위에서 모든 값이 거의 고른 빈도로 무작위수를 발생합니다)와 RandomN (Normal 을 의미합니다. 정규분포 무작위수를 발생합니다)의 전반적인 안내는 다음의 두 글을 참고하면 좋겠습니다. 이상우 화백의 글 답게, 제 글과 비교할 수 없는 미려한 그림을 기본으로 깔고 있습니다.

  • http://blog.daum.net/swrush/377
  • http://blog.daum.net/swrush/378