하드 디스크 어디선가 잠자고 있는 자료를 올립니다.
컴퓨터 프로그래밍으로 난수를 발생시키는 방법입니다.
난수 발생기
<원제: Quick and Portable Random
Number Generators>
● 글 \ Jerry Dwyer
필자 Jerry Dwyer는 시카고 대학에서 박사학위를 받았고
현재 클램슨 대학에서 경제학을 가르치고 있다.
통계분석과 실험치분석을 위하여 직접 프로그램을 작성하고 있다.
프로그래머로서의 경력은20여년이며C를사용한지도 10년이 지났다.
인터네트의 주소는 dwyerg@clemson.edu이다.
들어가며......
컴퓨터에서 난수를 발생한다는 것은 상당히 모순적인 이야기처
럼 들린다. 난수란 글자 그대로 예상할 수 없는 불규칙한 값이
다. 그러나 컴퓨터는 항상 같은 처리를 하기 때문에 결과가 예측
가능하다. 일반적으로 컴퓨터에서 말하는 난수 발생기는 특정
함수를 반복하여 일련의 불규칙한 수열을 얻는다. 이 수열이 임
의적으로 보일지라도 사실 컴퓨터에 의해 만들어지는 예측가능한
수열이다. 진정한 의미에서 난수라고 말하기 어렵다.
그러므로 이러한 난수는 '유사 난수'란 관점으로 보는 것이 정확
한 의미이다. 그러나 이 기사에서 '유사 난수'는 간단하게 '난수
'라고 부르기로 한다. 그러나 유사난수를 만드는 것은 쉬운 일이
아니다.
이 작업을 위하여 나는 다수의 자료를 참조해야 했으며 이를 참
조로 한 시뮬레이션을 해 왔다. 이 경험을 참조하여 독자에게 아
주 일반적으로 적용할 수 있는 난수 발생기를 설명하겠다.
기사에서 소스로 사용되는 C 언어는 ANSI C를 위주로 하였다.
그러므로 독자 여러분은 특정 컴파일러로 변환없이도 컴파일을
시켜볼 수 있다.
그리고 독자 여러분은 난수 발생기가 유지하는 값들이 어떻게
오버플로를 피하고 있는지 유의하여 살펴보기 바란다.
레머 발생기 (Lehmer Generators)
가장 많이 사용되는 난수 발생기는 1951년 레머 박사에 의해 고
안된 '배수 일치 난수 발생기'(간단히 레머 발생기라 칭함)이다.
레머 발생기는 다음의 재귀함수를 참조하고 있다.
x(t+1)=(a*x(t)) mod m
여기에서 x(t)는 t회 반복되었을 때의 값을 나타내는데 이 값은
결국 x(t+1)의 값을 만들어 내는 인자로 사용된다.
그리고 a는 승수를 mod는 모듈러 함수를 말한다. a*x의 값과 m
의 값이 모두 양수이면 모듈러 함수는 C에서 말하는 % 연산자와
같은 기능을 한다. 즉 모듈러 함수의 결과 값은 a*x-[a*x/m]*m의
결과와 같다.여기에서 []는 []안의 값보다 같거나 적은 가장 큰
정수를 나타낸다. C에 능통한 사람이라면 정수와 정수사이의 '/'
연산을 생각하면 된다.
난수 발생기의 계산에서 연속적인 값들 사이의 관계를 고려하면
좀더 이해하기 쉽다.<그림 1>은 x(t)가 1에서6까지 임의의 정수라
고 가정해서 x(t)와 x(t+1)사이의 관계를 보여 주는 그래프이다.
<그림 1> (A)는 실제 난수에 대한 그래프이다. 실제의 난수는
x(t)에서 발생하는 값이 x(t+1)에서 발생하는 값과 어떠한 관련도
맺지 않는다. 즉 완전한 형태의 난수 발생기는 2차원 그래프를 가
득 채워야한다.또 생성되는 수들은모두 같은 확률을 가지고 있다.
레머 발생기는 2차원 평면에서 이미 그 난수성을 상실하게 된
다. 예를 들어 다음 레머 발생기를 생각해 보자.
x(t+1)=(5*x(t)) mod 7
초기 값을 1로 했을 때 발생하는 난수는 1,5, 4, 6, 2, 3, 1
.........이다. 이 수열은 1에서 6까지 발생 가능한 수들이 실제
로 모두 발생하고 있다. 그러나 이 수열이 2차원 평면을 전부 채
우지 못한다. <그림 1>의 (b)는 x(t)와 x(t+1)이 어떤 관련을 갖
고 있음을 보여 준다. 즉 x(t)와 x(t+1)과의 한정된 쌍들만이 존
재하고 있다. 평면상의 모든 점들은 y=-2x+7, y=-2x+14 두 개의
직선 위에 존재하고 있다.
x(t), x(t+1)로 구성된 2차원 평면에서 한 차원 더 높게 생각해
보자. 즉 x(t), x(t+1), x(t+2)로 구성되는 3차원 평면에서 위 함
수를 재구성해 보자. 실제 난수들은 2차원에서처럼 3차원에서도
공간을 가득 채울 것이다. 그러나 레머 발생기는 공간을 메우는데
실패하고 점이나 선의 형태로서 3차원 공간에서 존재할 뿐이다.
이 특별한 구조적 모순은 레머 발생기에게는 피할 수 없는 운명
이다. 그러나 이 취약점이 레머 발생기가 가치가 없다고 단정짓는
근거가 될 수는 없다. 다른 난수 발생기들이 레머와는 다른 구조
를 가지고 있지만 위에서 제시된 문제를 해결하고 있는 발생기는
어디에도 없다.
레머 발생기는 승수 x(t)와 모듈러 m에 의하여 평면에 찍힐 수
의 위치가 결정된다. 그러면 문제의 방향은 레머 발생기가 가질
수밖에 없는 결정론적인 구조에서 벗어나 어떻게 승수 x(t)와 모
듈러 m의 값을 조정하여 주어진 한정적인 조건에서 가장 타당한
결과를 만들 수 있을까로 바뀐다.
레머 발생기가 가지는 결정론적 취약점 외에도 또 한 가지의 약
점을 가지고 있다. 바로 반복성이다. 승수 5와 모듈러 7의 상황에
서 레머 발생기는 주기를 6으로 하는 반복값을 가지게 된다. x(t)
의 값은 주기 6이 지난 후의 값인 x(t+6)의 값과 일치하게 된다.
그러나 반복 역시 레머 발생기에 한정된 문제는 아니다.
아무리 난해한 함수를 사용하여도 컴퓨터는 유한 개의 상황 속에
서 존재하기 때문에 결국 어느 시점에 가서는 이전의 상황으로 복
귀하게 되고 이때부터 다시 일련의 숫자들이 반복된다.
일반적으로 레머 발생기에 의하여 만들어지는 값 x(t)에 특정한
값을 더하는 절차를 만들어서 원시적인 레머 발생기를 세련되게
할 수 있다. 그러나 결과 값 x(t)에 증가 값을 둠으로서 생기는
문제가 있다.
레머 발생기가 0값을 가질 수도 있다는 것이다. 만약 레머 함수
가 한번 0의 값을 갖게 되면 이어지는 일련의 난수들이 모두 0의
값을 갖게되는 주기 1의 난수가 생기게 된다. 이런 수열은 난수로
서의 의미를 상실했다. 증가 값을 두는 것은 0의 값을 가질 수도
있음을 의미하기 때문에 설계자는 이 점을 반드시 고려하여 알고
리듬을 구성하여야 한다.
레머 발생기의 성능을 높이려면?
비록 레머 발생기가 반복적이고 결정론적인 값을 가진다고 하지
만 레머 발생기에도좋고 나쁨은 분명히 존재한다. 일례로 주기 값
을놓고 평가할 수도 있다.앞에서 살펴본 함수는 주시 값이 6이다.
x(t+1)=(5*x(t)) mod 7
6 주기의 값은 무척 짧은 값이다. 2^15(32,768)의 값도 복잡한
계산에서는 신빙성있는 난수 주기가 되지 못한다. 특히 컴파일러
제조업자는 이 말에 모두 동의할 것이다. 예를 들어 Borland
C++3.1과 마이크로소프트 사의 Vi-sual C 1.0의 경우에 32비트의
난수 발생기를 제공하고 있다. 물론 그 주기는 앞의 2^15이나
32,768의 값보다는 훨씬 길다(그러나 컴파일러가 제공하는 난수발
생기는 별로 매력적이지 못하다. 우선 이 기사에 나오는 함수보다
주기가 짧을 뿐 아니라 난수발생기가 이식성이 높지 못하여 오버
플로의 위험성도 있기 때문이다).
반복이 나타나지 않는다면 주기는 더 이상 우리의 관심의 대상
이 될 수 없다. 그러나 앞에서 설명했듯이 난수 발생기에서 반복
은 필연적이다. 그렇지만 우리가 주기가 매우 긴 난수 발생기를
만들 수 있고 애플리케이션은 일련의 난수 중 특정 부분만 사용한
다면 '유사 난수'가 특정 애플리케이션에, 한정적으로는 완벽한
난수로 역할을 할 수 있다. 이제 독자들도 이 글의 요지를 어림잡
을 수 있을 것이다. 앞에서 컴퓨터가 만들어 내는 난수의 한계
성을 고집스럽게 지속하면서 글을 계속한 이유는 바로 이런 눈속
임 때문이다. 난수는 필연적으로 반복할 수밖에 없지만 사용자의
관점에서는 얼마든지 이 반복을 피하여 일련의 수열중 특정 부분
만 사용하여 진정한 난수로 자리 매김을 할 수 있다는 것이다. 승
수와 모듈러는 주기값을 설정하는 데 결정적인 요소로 작용할 것
이며 이 값을 어떻게 조정하느냐가 난수 발생기의 좋은 알고리듬
을 결정하는 열쇠가 된다. 앞에서 제시된 승수와 모듈러의 값은
예시로 사용하기 위한 보기값에 불과하다.
주기6의 난수는 사실상 사용할 수 없다. 좀더 긴 주기를 갖는 난
수 발생기를 만들기 위하여 32비트 정수를 사용하여 보자.
긴 주기를 가지는 난수 발생기를 만들기 위하여 32비트 정수로
승수를 만든다. 승수와 모듈러수로 사용할 수 있는 수들은 많이
있다. 특히 승수와 모듈러의 수를 크게 하면 난수 주기는 일반적
으로 늘어나기 마련이다. 그러나 승수와 모듈러수는 모두가 CPU의
부하를 많이 차지한다는 사실을 고려할 때 무작정 크게 잡을 수는
없다. 그렇다면 어떤 값이 적당할까? 모듈러수로 많이 사용되는
수가 2^32이다.
왜일까? 앞에서 정의한 32비트의 부호 정수를 해머 발생기의 승수
로 사용한다는 사실을 고려해 보자.
x ← a * x
x가 가질 수 있는 최고 값은 2^31-1이다 32비트의 최상위 비트
는 부호비트로 사용된다. 특정 연산의 결과 값이 상위 비트로 캐
리지가 발생할 수도 있으며 결국 이 캐리지는 사인 버트에 영향을
미칠 수도 있다. 만약 이런 오버플로를 무시한다면 이 코드는
2^32의 모듈러수를 가지는 레머 발생기를 구현할 수 있다. 그러나
위의 기술은 오버플로를 무시한다는 가정에서 출발한 결론일 뿐이
다. 부호정수는 이런 류의 오버플로를 결코용납하지 않을 것이다.
ANSI C에서는 오버플로는 특별한 경우로 분류하고 그 동작의 처
리에 대해서는 정의하지 않겠다. 게다가 이 코드의 효과는 기계의
정수 표현 방식에 의존하고 있다. 기계나 언어 컴파일러나 심지어
컴파일러의 버전에 따라서 영향을 많이 받고 있기 때문에 프로그
램의 이식성을 보장하기는 어렵다. 함수를 더 빠르게 구현하여 속
도를 증가시키기보다는 이러한 비이식성을 제거하는데 시간을 투
자하는 것이 더 현명한 일이다.
모듈러값으로 많이 사용되는 또 다른 하나의 값은
2^31-1(2147483647) 이다. 왜일까? 이 값이야말로 최장의 주기를
가질 수 있는 최상의 선택이다.
더불어 베이식이나 포트란, 파스칼과 같은 언어의 컴파일러가
표현할 수 있는 최고의 부호 정수값이며 여러 기계에서도 이에 대
한 표현이 가능하다.
놀랍게도 더 큰 모듈러값(짝수)을 가지고 있는 난수 발생기의
주기가 작은 모듈러(홀수)의 주기에 반 정도밖에 안된다. 모듈러
수 2^32 에서는 초기 값이 홀수라면 주기는 거의 2^30 이른다.
2^31-1의 모듈러 수에서의 주기는 231-2에 이른다. 이 기사에서
사용하는 승수들을 테스트한 결과 모두2^31-1의 모듈러에서 최장
의 주기를 가졌다. 그리고 이 발생기를 기사 후반부에 나오는 결
합 알고리듬과 합칠 경우 그 주기는 거의 2^61이다. 여러 형태의
긴 주기 레머 발생기를 가지고 있다면 짧은 주기의 난수 발생기는
필요하지 않을 것이다.
승수의 값으로는 어떤 것이 좋을까? 여러분 스스로 승수를 구하
여 확인을 해 보는 걋?좋을 듯하다. 미안하지만 난수 발생기의
승수를 결정하는데 있어 어떠한 가이드 라인도 없다.
어떤 사람들은 이 승수들에 대한 연구를 위하여 많은 시간을 보
냈고 32비트의 부호 정수를 갖는 기계에서 이식성이 높은 32비트
난수 발생기를 만들기 위하여 연구하는 사람도 많이 있다.
이식성 높은 난수 발생기
이식성 높은 난수 발생기를 만들기 위하여 2^31-1의 모듈러 수
와 32비트 부호 정수를 사용한다는 것은 앞에서도 밝혔다. 이것은
결코 어려운 작업이 아니다.
가장 근본적인 문제는 오버플로의 해결이 될 것이다. 가장 최근
에 발생한 난수 x(t)와 승수(m)의 곱은 32비트 정수를 초과하는
경우가 발생하기 때문이다.
Linus Schrage는 위 곱셈의 결과를 모듈
Modulus Multiplier q r 10,000th
Draw
Alone
2^31-1 41,358 51,924 10,855 1,285,562,981
2^31-1 48,271 44,488 3,399 399,268,537
2^31-1 69,621 30,845 23,902 190,055,451
2^31-1 16,807 127,773 2,836 1,043,618,065
In combination generator
2,147,483,563 40,014 53,668 12,211 1,919,456,777
2,147,483,399 40,692 52,774 3,791 2,006,618,587
Combination generator with shuffling 804,307,721
Sources: Park and Miller [5]; L'Ecuyer [2,3]
<표 1> 레머 발생기에서 유용한 승수와 모듈러수
러수의 근사치 인수분해를 통하여 해결할 수 있는 방법을 연구하
였다. George Fishman과 Louis Moore는 2^31 -1의 모듈러 수를
가지는 레머 난수기에 대한 연구를 철저히 하여서 아래와 같은 결
론에 도달했다.
가장 좋은 승수들은 인수분해가 잘 될만큼 충분히 큰 수이어야
한다는 것이다. 그럼에도 불구하고 몇몇 승수는 아주 적음에도 불
구하고 똑같은 정도의 성능을 가지고 있다.
<표 1>은 자주 예시된 2^31-1의 모듈러값에 대한 4가지의 승수
를 비교한 값이다. 지난 25년 동안 많은 사람들이 애용한 값은
16,807이다.
알고리듬이 옳은지, 틀린지는 어떻게 확인을 할 것인가? 프로그
램의 실행결과로서 나오는 일련의 수들이 명백한 무작위성을 갖고
있다는 것을 확인하는 것은 중요한 작업이다. 그러나 이 작업은
사용하고 있는 프로그램을 통하여 확인하는 것으로 해결할 수가
없다. 프로그램의 오류를 찾는 것은 새로운 프로그램을 작성하는
것만큼이나 어려운 작업이기 때문이다. 방법은 직접 발생하는 값
들을 확인하는 수뿐이다. <표 1>에서 초기값을 1로 하여 10,000번
째 시행되었을 때 난수 발생기가 만들어 내는 값을 보여 주고 있
다. 이 작업은 DOS와 OS/2에서 Mathematica와 Borland C를 사용하
여 나온 결과이다.
여러분의 프로그램에 이상이 있다면 같은 초기 값을 가지고 출
발한 발생기가 10,000번째 같은 값을 가질 확률은 거의 0에 가깝
다고 보아도 무방할 것이다. 이것은 <리스트 1>은 rand.ma라는 파
일을 보여 주고 있는데 이 파일은 Mathematica 프로그램에서
10,000번째의 값을 구해 주는 프로그램이다. <리스트 2>의 하단부
에 있는 C 코드로 부터 나온 결과를 확인하는데 편리한 방식을 제
시하고 있다.
<리스트 2>(rand_por.c)는 특별한 승수에 대한 이식성 높은 함수
를 구현한 것이다. 초기화 코드는 특정 컴파일러에서 오버플로를
만들 수도있다. 그러나 코드의 나머지 부분은 이식성을 보장할 수
가 있다. 이 코드에서 가독성과 속도사이에 선택을 할 필요가 있
을 때마다 나타나는 가독성을 우선시하였다. 가독성에서 가장 중
요시해야 할 부분은 genr_rand_port함수에서 보여지는 난수 발생
기의 구현이다.
이 함수는 4개의 기본적인 외부함수를 갖고 있다. init_rand와
rand_port의 두 함수는 표준 C함수의 srand, rand와 상당히 유사
한 면을 갖고 있다. 여러분이 srand, rand 함수를 통하여 예상하
듯이 init_rand와 rand_port는 동작을 할 것이다. 또 다른 함수
로 get_init_rand와 rand_rect_port가 있다. get_init_rand함수는
init_rand함수로 결과 값을 넘기기 위하여 사용한다고 생각하면
된다. 잘못된 값으로 init_rand를 호출했다면(0이나 -1과 같
은), init_rand_port함수는 에러처리 루틴 값을 받기 위하여
get_init_rand_port를 호출하게 된다. init_rand_port로부터 복귀
된 값은 난수 발생기를 재가동시킬 인자로 사용되어 발생기가 똑
같은 난수를 만들어 내도록 할 것이다. 일반적으로 사용되는 에러
처리 루틴 값은 1이기 때문에 함수들은 초기 값을 무시하는 경향
이 있다. 왜냐하면 에러 처리 루틴 값 1에서 만들어지는 난수가
임의성이 크지 못하기 때문이다. 승수와 제곱수에 많은 차이가 있
다고 생각하면 될 것이다. Start up-RANDS로 정의한 16의 값도 이
런 임의성을 반영한 결과이다.
<리스트 2>의 rand_rect_port함수는 0에서 1사이의 어떤 값을
만들어 낸다. 이 값은 0과 1사이에서 정형적인 분산의 성격을 띈
값이다.
이 함수는 레머 발생기에서 나온 값을 모듈러로 나눈다. 레머
발생기가 어떤 시점에서도 0이나 모듈러와 같은 값은 만들 수는
없다. 그러므로 이함수의 결과는언제나 0에서 1사이가 될 것이다.
Monte Carlo의 연구에 의하면 난수가 겹치지 않게 만드는 것이
바람직하다고 한다. <리스트 2>는 init_rand에 의하여 이전에 만
들어 진 값들을 제외시키기 위하여 skip_ahead라는 함수를 사용하
고 있다. rand-pont 함수는 초기 값에서부터 t번째의 값 x(t)를
구한다. 4,000번째나 1,000번째 같은.......
이 함수는 중간값을 계산하는 과정이 다소빠릿? 오버플로우가
없는 이 계산은 희망하는 출력 값을 얻기 위해서는 다음과 같은
주의사항이 있다.
(a^skip * init_rand) mod m
모듈러 수 m보다 skip의 값이 반드시 작아야 한다. skip_ahead
와 mult_mod함수는 오버플로우를 피하기 위하여 근사치 인수분해
와 함께 Russian Peasant 알고리듬을 사용하고 있다.
'세상에 공짜는 없다'는 말처럼 이식성과 긴 주기를 보장하기
위해서는 필연적으로 속도에 문제를 일으키기 마련이다. 필자의
개인적인 의견으로는 속도에서 오는 손실(단순한 속도의 저하가
아니라 타당한 속도를 유지하기 위하여 발생되는 난수 발생기 프
로그램을 운영하는 기계의 확장)은 큰 문제가 아니라고 생각한다.
rand_port함수는 결코 느리다고 말할 수 없다. 필자가 보유하고
있는 66MHz 486컴퓨터와 OS/2의 환경에서 100,000개의 난수를 발
생하는데 약 0.23초가 소요되었다. 이것은 Borland의 오버플로를
사용하였을 때 걸린 시간인 0.09초와 비교가 된다. 성능이 심각한
문제를 야기시키는 것은 16비트 도스 환경에서이다. 이식성 함수
는 Borand 함수가 0.22초가 걸린 것에 비하여 약 1.5초 정도가 더
소요되었다. 그러나 필자는 같은 가격에서는 이식성이 높고 약 2
배의 주기를 가지고 있는(더구나 이 함수는 이전에 발생한 값을
피할 수도 있다) 레머 발생기를 취하겠다.
결합과 혼합
약 21억?해당하는2^31-2의 값이 여러 목적에 이용하기에 결코
작은 값이 아니기 때문에 더 큰 주기의 난수 발생기를 별도로 필
요로 하는 경우는 발생하지 않는다. 그러나 레머 발생기는 일단
완전히 주기에 돌입해야 비로소 신뢰성있는 결과를 만들어 낸다.
도입부에서 살펴본 <그림 1>의 그래프는 난수 발생기의 사용에
있어서 문제가 되는 요소를 보여 주고 있다.
이 문제와 주기의 문제를 완화시킬 수 있는 두 가지 기술이 있
는데 하나가 결합이고 다른 하나는 혼합이다.
레머 발생기에서 나온 값들을 결합하는 것은 그 합이나 차를 이
용하여 결과를 만든다는 것이다. L'Ecuyer는 <그림 1>과 같은 평
면의 문제를 효과적으로 없애기 위하여 두 수의 차를 이용할 것을
제안한다. <리스트 3>의 레머 발생기의 값들의 차는 약
2.31x10^18 의 주기를 갖게 된다.
난수 발생기의 결과 값을 혼합하는 것은 주기의 길이와 임의성
의 보장이라는 측면에서 또 다른 해결 방안을 제시한다. 기본적인
생각은 무척 단순하게 보인다. 레머 발생기의 수열만을 취하기 보
다는 몇 개의 값을 기억시켜 놓고 그 중 하나를 임의적으로 뽑아
서 사용한다는 것이다.
특정 승수나 모듈러 수에서 발생기의 값을 섞어서 주기를 실제
적으로 연장시키는 것은 분석적으로 결론을 내리기가 어렵다. 그
러나 이 기술은 최소한 난수 발생기의 성능을 저하시키지는 않을
것이다 일련의 수는 연속된 값의 집합은 아니기 때문에 더욱 임
의적으로 보인다. 혼합은 특별히 난수 발생기가 최악의 상황에 도
달했을 때 빛을 발한다. 왜냐하면 이전에 정장된 값들이 현재의
난수 발생기가 처한 문제를 해결할 수있는 열쇠가 되기 때문이다.
<그림 3>의 Rand_com.c파일은 두 개의 난수 발생기의 결과를 결
합하고 혼합하는 함수이다. 위에서의 <표1>은 두 개의 난수 발생
기를 결합하였을 때의 10,000번째의 결과 값을 보여 주고 있다.
<리스트 3>은 이전 값을 제외시킨 skip_ahead 과정이 제외되었
다. 난수 발생기의 결과 값을 혼합시킨다면 이전에 나온 난수가
주기 내에는 다시 나오지 않는다는 보장을 할 수 없기 때문이다.
그러나 2.31x 10^18의 주기를 조금 줄일 수 있는 여유가 있다면
<리스트 2>의 skip ahead함수를 이용하기 위하여 <리스트 3>도 수
정할 수 있을 것이다. <리스트 3>의 혼합과정을 제외하고 <리스트
2>의 skip ahead 함수를 적용하면 된다.
결과적으로 여러분이 잘 작동하고 빠르며 똑같은 정도의 확률을
가지는 난수 발생기를 원한다면 필자는 rand_port를 추천할 수 있
다. 만약 여러분이 더 긴 주기를 가지며 비록 속도면에서 저하가
발생하는 한이 있어도 난수로서의 성격이 더 분명한 함수를 희망
한다면 필자는 rand_comb를 추천한다.
참 고 서 적
[1] George S. Fishman and Louis R. Moore III.
"An Exhaustive Analysis of Multiplicative Co
ngruential Random-Number Generators with M
odulus 2^31-1"
SIAM Journal on Scientific and Statistical Co
mputing January: 1986
[2] Pierre L'Ecuyer.
"Efficient and Portable Combined Random
Number Generators"
Communications of the ACM June: 1988
[3] Pierre L'Ecuyer
"Random Numbers for Simulation"
Communications of the ACM October: 1990
[4] Donald Knuth
The Art of Computer Programming, Vol 2,
"Seminumerical Algorithms"
Reading MA:Addison Wesley, 1981 pp441-
443
더 깊게 공부하고 싶다면......
독자 여러분이 난수 발생기에 관한 더 많은 지식을 쌓고 싶다면
위에서 언급한 Donald Knuth의 저서 제 3장에서부터 시작하기를
권한다.
이 책은 난수 발생기에 관하여 고전이 된 책이다. 고전이 가지
고 있는 의미에는 두 가지가 있다. 그 첫 번째가 시기적으로 뒤쳐
졌다는 말이다. Bratley, Fox, Schrage는 Donald보다 훨씬 나은
관점을 제시하고 있다. James는 선택적 난수 발생기라는 분야에서
독보적인 자리를 차지하고 있다. 여러분이 쉽게 접할 수 있는 책
을 아래에 기록하였으니 앞으로도 지속적으로 참조하기 바란다.
Bratley, Paul, Bennett L. Fox and Linux E. Schrage.
A Guide to Simulation, Second Edition.
New York NY: Springer Verlag, 1987
James, F.
"A Review of Pseudorandom Number Generators"
Computer Physics Communications.
October 1990
Press, William H., et al.
Numerical Recipes in C, Second Edition.
Cambridge: Cambridge University Press, 1992
Park, Stephen K. and Keith W. Miller.
"Random-Number Generators: Good Ones Ard
Hard to Find"
Communications of the ACM. October 1988
L'Ecuyer, Pierre, and Serge Coti.
"Implementing a Random-Number Package
with Splitting Facilities"
ACM Transactions on Mathematical Software.
March 1991
|