난수 스트림을 만들고 제어하기
RandStream
클래스를 사용하면 난수 스트림을 만들 수 있습니다. 이 클래스는 여러 이유로 유용합니다.
전역 스트림의 상태에 영향을 미치지 않고 난수 값을 생성할 수 있습니다.
시뮬레이션에서 임의성을 주는 별도의 소스를 사용할 수 있습니다.
MATLAB®이 시작 시에 사용하는 것과 다르게 구성된 생성기를 사용할 수 있습니다.
RandStream
객체를 통해 자신만의 스트림을 만들고, 쓰기 가능한 속성을 설정하며 스트림을 사용하여 난수를 생성할 수 있습니다. 전역 스트림을 제어하는 것과 동일한 방식으로, 사용자가 만든 스트림을 제어할 수 있습니다. 전역 스트림을 사용자가 만든 스트림으로 교체할 수도 있습니다.
스트림을 만들려면 RandStream
함수를 사용하십시오.
myStream = RandStream('mlfg6331_64');
rand(myStream,1,5)
ans = 0.6986 0.7413 0.4239 0.6914 0.7255
난수 스트림 myStream
은 전역 스트림과 별개로 동작합니다. myStream
을 첫 번째 인수로 사용하여 rand
, randn
, randi
, randperm
함수를 호출하면 사용자가 만든 스트림에서 추출합니다. myStream
을 사용하지 않고 rand
, randn
, randi
, randperm
함수를 호출하면 전역 스트림에서 추출합니다.
RandStream.setGlobalStream
메서드를 사용하여 myStream
을 전역 스트림으로 만들 수 있습니다.
RandStream.setGlobalStream(myStream) RandStream.getGlobalStream
ans = mlfg6331_64 random stream (current global stream) Seed: 0 NormalTransform: Ziggurat
RandStream.getGlobalStream == myStream
ans = 1
서브스트림
서브스트림을 사용하여 스트림과 통계적으로 독립적인 다른 결과를 얻을 수 있습니다. 난수열에서의 위치를 정확하게 알 수 없는 시드값과 달리 서브스트림 간 간격은 알 수 있으므로 중첩을 방지할 수 있습니다. 간단히 말해서 서브스트림은 기존에 시드값을 사용해서 했던 일을 더 세심히 조정된 방식으로 하기 위한 방법입니다. 또한 서브스트림은 병렬 스트림보다 더 간단한 솔루션입니다.
서브스트림은 동일한 코드에서 다른 시간에 다른 결과를 얻을 수 있는 빠르고 쉬운 방법을 제공합니다. RandStream
객체의 Substream
속성을 사용하려면 서브스트림을 지원하는 생성기를 사용하여 스트림을 만드십시오. 서브스트림을 지원하는 생성기 알고리즘과 해당 속성에 대한 목록은 다음 섹션의 테이블을 참조하십시오. 예를 들어, 루프에서 여러 개의 난수를 생성해 보겠습니다.
myStream = RandStream('mlfg6331_64'); RandStream.setGlobalStream(myStream) for i = 1:5 myStream.Substream = i; z = rand(1,i) end
z = 0.6986 z = 0.9230 0.2489 z = 0.0261 0.2530 0.0737 z = 0.3220 0.7405 0.1983 0.1052 z = 0.2067 0.2417 0.9777 0.5970 0.4187
다른 루프에서 첫 번째 5회 반복 세트와 독립적인 난수 값을 생성할 수 있습니다.
for i = 6:10 myStream.Substream = i; z = rand(1,11-i) end
z = 0.2650 0.8229 0.2479 0.0247 0.4581 z = 0.3963 0.7445 0.7734 0.9113 z = 0.2758 0.3662 0.7979 z = 0.6814 0.5150 z = 0.5247
서브스트림은 직렬 계산에 유용합니다. 서브스트림은 스트림 내 특정 검사 지점으로 돌아가 시뮬레이션 전체나 일부를 다시 만들 수 있습니다. 예를 들어, 루프에서 6번째 서브스트림으로 돌아갈 수 있습니다. 결과에 위의 6번째 출력과 같은 값이 포함되어 있습니다.
myStream.Substream = 6; z = rand(1,5)
z = 0.2650 0.8229 0.2479 0.0247 0.4581
난수 생성기 선택하기
MATLAB은 여러 가지 생성기 알고리즘 옵션을 제공합니다. 표에는 사용 가능한 생성기 알고리즘의 주요 속성과 이를 만드는 데 사용되는 키워드가 요약되어 있습니다. 사용 가능한 생성기 알고리즘의 전체 목록을 반환하려면 RandStream.list
메서드를 사용하십시오.
키워드 | 생성기 | 다중 스트림 및 서브스트림 지원 여부 | 최대 정밀도의 근사 주기 |
---|---|---|---|
mt19937ar | 메르센 트위스터 | 아니요 | 219937-1 |
dsfmt19937 | SIMD 기반 고속 메르센 트위스터 | 아니요 | 219937-1 |
mcg16807 | 승산식 합동법 생성기 | 아니요 | 231-2 |
mlfg6331_64 | 시차 피보나치 수열 생성기 | 예 | 2124(길이가 272인 251개의 스트림) |
mrg32k3a | 결합 다중 재귀적 생성기 | 예 | 2191(길이가 2127인 263개의 스트림) |
philox4x32_10 | 10회 라운드의 Philox 4x32 생성기 | 예 | 2193(길이가 2129인 264개의 스트림) |
threefry4x64_20 | 20회 라운드의 Threefry 4x64 생성기 | 예 | 2514(길이가 2258인 2256개의 스트림) |
shr3cong | 선형 합동법 생성기로 계산된 시프트 레지스터 생성기 | 아니요 | 264 |
swb2712 | 수정된 자리 내림을 사용하는 뺄셈 생성기 | 아니요 | 21492 |
생성기 mcg16807
, shr3cong
, swb2712
는 이전 MATLAB 버전과의 호환성을 위해 제공됩니다. mt19937ar
과 dsfmt19937
은 기본적으로 순차적인 애플리케이션을 위해 설계되었습니다. 나머지 생성기는 병렬 난수 생성에 대한 명시적인 지원을 제공합니다.
응용 사례에 따라 일부 생성기는 속도가 더 빠르거나 더욱 정밀한 값을 반환할 수도 있습니다. 모든 의사 난수 생성기는 결정론적 알고리즘을 바탕으로 하며, 모든 생성기는 충분히 구체적인 통계적 임의성 검정에 통과합니다. 몬테카를로(Monte Carlo) 시뮬레이션의 결과를 확인하는 한 가지 방법은 두 개 이상의 각기 다른 생성기 알고리즘을 사용하여 시뮬레이션을 다시 실행하는 것이며, MATLAB이 선택하는 생성기에 따라 이를 수행하는 방법이 제공됩니다. 각기 다른 생성기를 사용하는 경우 결과가 몬테카를로 샘플링 오차 이상으로 달라질 가능성은 낮지만, 문서에 이러한 유형의 확인(Validation)을 통해 특정 생성기 알고리즘의 결함이 확인된 예제가 나와 있습니다. 예제는 [13] 항목을 참조하십시오.
생성기 알고리즘
mt19937ar
메르센 트위스터([11]에 설명되어 있음)는 주기가 이며, 각 U(0,1) 값은 2개의 32비트 정수를 사용하여 생성됩니다. 가능한 값은 구간 (0, 1) 내에 있는 의 배수입니다. 이 생성기는 다중 스트림이나 서브스트림을 지원하지 않습니다.
mt19937ar
스트림에 기본적으로 사용되는randn
알고리즘은 지구라트 알고리즘 [7]이지만, 그 기반에는mt19937ar
생성기가 있습니다.참고
이 생성기는 MATLAB 버전 7부터
rand('twister',s)
로 활성화되는rand
함수에서 사용하는 생성기와 동일합니다.dsfmt19937
배정밀도 SIMD 기반 고속 메르센 트위스터([12]에 설명되어 있음)는 메르센 트위스터 알고리즘보다 구현 속도가 더 빠릅니다. 주기는 이고, 가능한 값은 구간 (0, 1) 내에 있는 의 배수입니다. 이 생성기는 기본적으로 [1, 2)에 포함되는 배정밀도 값을 생성하고, 이러한 값은 U(0,1) 값을 생성하도록 변환됩니다. 이 생성기는 다중 스트림이나 서브스트림을 지원하지 않습니다.
-
mcg16807
승수 , 모듈로 을 사용하는 32비트 승산식 합동법(Multiplicative Congruential) 생성기입니다([14]에 설명되어 있음). 이 생성기는 주기가 이며, 다중 스트림이나 서브스트림을 지원하지 않습니다. 각 U(0,1) 값은 생성기에서 단일 32비트 정수를 사용하여 생성됩니다. 가능한 값은 엄격하게 구간 (0, 1) 내에 있는 모든 의 배수입니다.
mcg16807
스트림의 경우randn
에서 사용되는 디폴트 알고리즘은 극좌표 알고리즘입니다([1]에 설명되어 있음).참고
이 생성기는 MATLAB 버전 4부터
rand('seed',s)
나randn('seed',s)
를 사용하여 활성화되는rand
함수와randn
함수에서 사용하는 생성기와 동일합니다.mlfg6331_64
지연값(lags) , 을 사용하는 64비트 시차 피보나치 수열(Multiplicative Lagged Fibonacci) 생성기입니다([10]에 설명되어 있음). 이 생성기는 SPRNG 라이브러리에 구현된 MLFG와 유사합니다. 이 생성기는 주기가 대략적으로 입니다. 또한, 파라미터화를 통해 최대 개의 병렬 스트림을 지원하고, 각각 길이가 인 개의 서브스트림을 지원합니다. 각 U(0,1) 값은 생성기에서 64비트 정수 하나를 사용하여 생성됩니다. 가능한 값은 엄격하게 구간 (0, 1) 내에 있는 의 모든 배수입니다.
mlfg6331_64
스트림에 기본적으로 사용되는randn
알고리즘은 지구라트 알고리즘 [7]이지만, 그 기반에는mlfg6331_64
생성기가 있습니다.mrg32k3a
32비트 결합 다중 재귀적(Combined Multiple Recursive) 생성기입니다([2]에 설명되어 있음). 이 생성기는 C로 작성된 RngStreams 패키지에 구현된 CMRG와 유사합니다. 이 생성기는 주기가 이며 수열 분할을 통해 각각 길이가 인 최대 개의 병렬 스트림을 지원합니다. 또한 각각 길이가 인 개의 서브스트림도 지원합니다. 각 U(0,1) 값은 생성기에서 2개의 32비트 정수를 사용하여 생성됩니다. 가능한 값은 엄격하게 구간 (0, 1) 내에 있는 의 배수입니다.
mrg32k3a
스트림에 기본적으로 사용되는randn
알고리즘은 지구라트 알고리즘 [7]이지만, 그 기반에는mrg32k3a
생성기가 있습니다.philox4x32_10
10회 라운드의 4x32 생성기입니다([15]에 설명되어 있음). 이 생성기는 파이스텔 구조(Feistel Network)와 정수 곱셈을 사용합니다. 이 생성기는 GPU 같은 고도 병렬 시스템의 고성능을 지원하기 위해 특별히 설계되었습니다. 주기는 2193(길이가 2129인 264개 스트림)입니다.
threefry4x64_20
20회 라운드의 4x64 생성기입니다([15]에 설명되어 있음). 이 생성기는 스케인 해시 함수(Skein Hash Function)에서 스리피시 블록 암호(Threefish Block Cipher)를 비암호화 방식으로 조정한 것입니다. 주기는 2514(길이가 2258인 2256개 스트림)입니다.
shr3cong
승수(Multiplier) , 가수(Addend) , 모듈로(Modulus) 을 사용하여 선형 합동법 생성기로 계산된, 마르사글리아(Marsaglia)의 SHR3 시프트 레지스터 생성기입니다. SHR3은 으로 정의되는 3 시프트 레지스터 생성기입니다. 여기서 는 단위 연산자이고, 은 왼쪽 시프트 연산자이며, R은 오른쪽 시프트 연산자입니다. 결합 생성기(SHR3 부분은 [7]에 설명되어 있음)는 주기가 대략적으로 입니다. 이 생성기는 다중 스트림이나 서브스트림을 지원하지 않습니다. 각 U(0,1) 값은 생성기에서 32비트 정수 하나를 사용하여 생성됩니다. 가능한 값은 엄격하게 구간 (0, 1) 내에 있는 의 모든 배수입니다.
shr3cong
스트림에 기본적으로 사용되는randn
알고리즘은 이전 형식의 지구라트 알고리즘 [9]이지만, 그 기반에는shr3cong
생성기가 있습니다. 이 생성기는 MATLAB 버전 5부터randn('state',s)
를 사용하여 활성화되는randn
함수에서 사용하는 생성기와 동일합니다.swb2712
수정된 자리 내림을 사용하는 뺄셈(Subtract-with-Borrow) 생성기입니다([8]에 설명되어 있음). 이 생성기는 지연값(lags) 27과 12를 사용하는 가산식 시차 피보나치(Additive Lagged Fibonacci) 생성기와 유사하지만, 대략적으로 의 더 긴 주기를 갖도록 변형되었습니다. 이 생성기는 기본적으로 배정밀도로 동작하여 U(0,1) 값을 만들고, 열린 구간 (0, 1) 내에 있는 모든 값이 가능합니다.
swb2712
스트림에 기본적으로 사용되는randn
알고리즘은 지구라트 알고리즘 [7]이지만, 그 기반에는swb2712
생성기가 있습니다.참고
이 생성기는 MATLAB 버전 5부터
rand('state',s)
를 사용하여 활성화되는rand
함수에서 사용하는 생성기와 동일합니다.
변환 알고리즘
RandStream
을 사용하여 난수 스트림을 만들 때 'Ziggurat'
, 'Polar'
또는 'Inversion'
알고리즘 중 하나를 사용하여 NormalTransform
이름-값 인수를 지정할 수 있습니다. 이 알고리즘은 균일 난수 생성기를 가우스 생성기로 변환하여, randn
을 사용해 정규분포된 난수를 생성할 수 있게 해 줍니다. 알고리즘에 대한 자세한 내용은 [16] 항목을 참조하십시오.
Inversion
표준 정규 역누적 분포 함수(Standard Normal Inverse Cumulative Distribution Function)를 균일 확률 변량에 적용하여 정규 확률 변량을 계산합니다. 정규 값당 정확히 하나의 균일 값이 사용됩니다.
Polar
극값 거부 알고리즘(Polar Rejection Algorithm)입니다([1]에 설명되어 있음). 평균적으로 정규 값당 대략 1.27개의 균일 값이 사용됩니다.
Ziggurat
지구라트 알고리즘입니다([7]에 설명되어 있음). 평균적으로 정규 값당 대략 2.02개의 균일 값이 사용됩니다.
스트림 구성하기
난수 스트림 s
에는 s의 동작을 제어하는 속성이 있습니다. 속성에 액세스하거나 속성을 변경하려면 구문 p = s.Property
와 s.Property = p
를 사용하십시오.
예를 들어, randn
을 사용할 때 정규분포 의사 난수 값을 생성하도록 변환 알고리즘을 구성할 수 있습니다. 디폴트 Ziggurat
변환 알고리즘을 사용하여 정규분포 의사 난수 값을 생성합니다.
s1 = RandStream('mt19937ar');
s1.NormalTransform
ans = 'Ziggurat'
r1 = randn(s1,1,10);
Polar
변환 알고리즘을 사용하여 정규분포 의사 난수 값을 생성하도록 스트림을 구성합니다.
s1.NormalTransform = 'Polar'
s1 = mt19937ar random stream Seed: 0 NormalTransform: Polar
r2 = randn(s1,1,10);
rand
를 사용하여 균등분포 난수를 생성하는 경우 대조 의사 난수 값(즉, 균일 값인 경우 1에서 보통의 값을 뺀 값)을 생성하도록 스트림을 구성할 수도 있습니다.
스트림 s에서 균등분포된 6개의 난수를 만듭니다.
s2 = RandStream('mt19937ar');
r1 = rand(s2,1,6)
r1 = 0.8147 0.9058 0.1270 0.9134 0.6324 0.0975
스트림의 초기 상태를 복원합니다. Antithetic
속성이 true로 설정된 다른 6개의 난수를 만듭니다. 이 6개의 난수가 1에서 앞서 생성된 난수를 뺀 값과 같은지 확인합니다.
reset(s2) s2.Antithetic = true; r2 = rand(s2,1,6)
r2 = 0.1853 0.0942 0.8730 0.0866 0.3676 0.9025
isequal(r1,1 - r2)
ans = 1
스트림 속성을 하나씩 설정하는 대신 A = get(s)
와 set(s,A)
를 각각 사용하여 스트림 s
의 모든 속성을 저장하고 복원할 수 있습니다. 예를 들어, 스트림 s2
의 모든 속성이 스트림 s1
과 같도록 구성해 보겠습니다.
A = get(s1)
A = Type: 'mt19937ar' NumStreams: 1 StreamIndex: 1 Substream: 1 Seed: 0 State: [625x1 uint32] NormalTransform: 'Polar' Antithetic: 0 FullPrecision: 1
set(s2,A)
Type: 'mt19937ar' NumStreams: 1 StreamIndex: 1 Substream: 1 Seed: 0 State: [625x1 uint32] NormalTransform: 'Polar' Antithetic: 0 FullPrecision: 1
get
함수와 set
함수를 사용하면 나중에 결과를 똑같이 재현할 수 있도록 스트림의 전체 구성을 저장하고 복원할 수 있습니다.
난수 생성기 상태를 복원하여 출력 재현하기
State
속성은 난수 생성기의 내부 상태입니다. 난수를 생성할 때 시뮬레이션의 특정 지점에서 전역 스트림의 상태를 저장하여 나중에 결과를 재현할 수 있습니다.
RandStream.getGlobalStream
을 사용하여 전역 스트림(즉, rand
가 난수를 생성하는 기반이 되는 현재 전역 스트림)에 대한 핸들을 반환합니다. 전역 스트림의 상태를 저장합니다.
globalStream = RandStream.getGlobalStream; myState = globalStream.State;
myState
를 사용하여 globalStream
의 상태를 복원하고 이전 결과를 다시 생성할 수 있습니다.
A = rand(1,100); globalStream.State = myState; B = rand(1,100); isequal(A,B)
ans = logical 1
rand
, randi
, randn
, randperm
은 전역 스트림에 액세스합니다. 이들 함수는 모두 동일한 기본 스트림에 액세스하므로, 한 함수를 호출할 경우 후속 호출 시 다른 함수에서 생성되는 값에 영향을 미칩니다.
globalStream.State = myState; A = rand(1,100); globalStream.State = myState; C = randi(100); B = rand(1,100); isequal(A,B)
ans = logical 0
또한 reset
함수를 사용하여 스트림을 해당 초기 설정으로 재설정할 수도 있습니다.
reset(globalStream) A = rand(1,100); reset(globalStream) B = rand(1,100); isequal(A,B)
ans = logical 1
참고 문헌
[1] Devroye, L. Non-Uniform Random Variate Generation, Springer-Verlag, 1986.
[2] L’Ecuyer, P. “Good Parameter Sets for Combined Multiple Recursive Random Number Generators”, Operations Research, 47(1): 159–164. 1999.
[3] L'Ecuyer, P. and S. Côté. “Implementing A Random Number Package with Splitting Facilities”, ACM Transactions on Mathematical Software, 17: 98–111. 1991.
[4] L'Ecuyer, P. and R. Simard. “TestU01: A C Library for Empirical Testing of Random Number Generators,” ACM Transactions on Mathematical Software, 33(4): Article 22. 2007.
[5] L'Ecuyer, P., R. Simard, E. J. Chen, and W. D. Kelton. “An Objected-Oriented Random-Number Package with Many Long Streams and Substreams.” Operations Research, 50(6):1073–1075. 2002.
[6] Marsaglia, G. “Random numbers for C: The END?” Usenet posting to sci.stat.math. 1999. Available online at https://groups.google.com/group/sci.crypt/browse_thread/
.
thread/ca8682a4658a124d/
[7] Marsaglia G., and W. W. Tsang. “The ziggurat method for generating random variables.” Journal of Statistical Software, 5:1–7. 2000. Available online at https://www.jstatsoft.org/v05/i08
.
[8] Marsaglia, G., and A. Zaman. “A new class of random number generators.” Annals of Applied Probability 1(3):462–480. 1991.
[9] Marsaglia, G., and W. W. Tsang. “A fast, easily implemented method for sampling from decreasing or symmetric unimodal density functions.” SIAM J. Sci. Stat. Comput. 5(2):349–359. 1984.
[10] Mascagni, M., and A. Srinivasan. “Parameterizing Parallel Multiplicative Lagged-Fibonacci Generators.” Parallel Computing, 30: 899–916. 2004.
[11] Matsumoto, M., and T. Nishimura.“Mersenne Twister: A 623-Dimensionally Equidistributed Uniform Pseudorandom Number Generator.” ACM Transactions on Modeling and Computer Simulation, 8(1):3–30. 1998.
[12] Matsumoto, M., and M. Saito.“A PRNG Specialized in Double Precision Floating Point Numbers Using an Affine Transition.” Monte Carlo and Quasi-Monte Carlo Methods 2008, 10.1007/978-3-642-04107-5_38. 2009.
[13] Moler, C.B. Numerical Computing with MATLAB. SIAM, 2004. Available online at https://www.mathworks.com/moler
[14] Park, S.K., and K.W. Miller. “Random Number Generators: Good Ones Are Hard to Find.” Communications of the ACM, 31(10):1192–1201. 1998.
[15] Salmon, J. K., M. A. Moraes, R. O. Dror, and D. E. Shaw. "Parallel Random Numbers: As Easy As 1, 2, 3." In Proceedings of the International Conference for High Performance Computing, Networking, Storage and Analysis (SC11). New York, NY: ACM, 2011.
[16] Thomas, D. B., P. H. W. Leong, and J. D. Villasenor. “Gaussian Random Number Generators.”ACM Computing Surveys, 39(4): 11-es. 2007.