Main Content

난수 스트림을 만들고 제어하기

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
dsfmt19937SIMD 기반 고속 메르센 트위스터 아니요219937-1
mcg16807승산식 합동법 생성기아니요231-2
mlfg6331_64시차 피보나치 수열 생성기2124(길이가 272인 251개의 스트림)
mrg32k3a결합 다중 재귀적 생성기2191(길이가 2127인 263개의 스트림)
philox4x32_1010회 라운드의 Philox 4x32 생성기2193(길이가 2129인 264개의 스트림)
threefry4x64_2020회 라운드의 Threefry 4x64 생성기2514(길이가 2258인 2256개의 스트림)
shr3cong선형 합동법 생성기로 계산된 시프트 레지스터 생성기아니요264
swb2712수정된 자리 내림을 사용하는 뺄셈 생성기아니요21492

생성기 mcg16807, shr3cong, swb2712는 이전 MATLAB 버전과의 호환성을 위해 제공됩니다. mt19937ardsfmt19937은 기본적으로 순차적인 애플리케이션을 위해 설계되었습니다. 나머지 생성기는 병렬 난수 생성에 대한 명시적인 지원을 제공합니다.

응용 사례에 따라 일부 생성기는 속도가 더 빠르거나 더욱 정밀한 값을 반환할 수도 있습니다. 모든 의사 난수 생성기는 결정론적 알고리즘을 바탕으로 하며, 모든 생성기는 충분히 구체적인 통계적 임의성 검정에 통과합니다. 몬테카를로(Monte Carlo) 시뮬레이션의 결과를 확인하는 한 가지 방법은 두 개 이상의 각기 다른 생성기 알고리즘을 사용하여 시뮬레이션을 다시 실행하는 것이며, MATLAB이 선택하는 생성기에 따라 이를 수행하는 방법이 제공됩니다. 각기 다른 생성기를 사용하는 경우 결과가 몬테카를로 샘플링 오차 이상으로 달라질 가능성은 낮지만, 문서에 이러한 유형의 확인(Validation)을 통해 특정 생성기 알고리즘의 결함이 확인된 예제가 나와 있습니다. 예제는 [13] 항목을 참조하십시오.

생성기 알고리즘

mt19937ar

메르센 트위스터([11]에 설명되어 있음)는 주기가 2199371이며, 각 U(0,1) 값은 2개의 32비트 정수를 사용하여 생성됩니다. 가능한 값은 구간 (0, 1) 내에 있는 253의 배수입니다. 이 생성기는 다중 스트림이나 서브스트림을 지원하지 않습니다. mt19937ar 스트림에 기본적으로 사용되는 randn 알고리즘은 지구라트 알고리즘 [7]이지만, 그 기반에는 mt19937ar 생성기가 있습니다.

참고

이 생성기는 MATLAB 버전 7부터 rand('twister',s)로 활성화되는 rand 함수에서 사용하는 생성기와 동일합니다.

dsfmt19937

배정밀도 SIMD 기반 고속 메르센 트위스터([12]에 설명되어 있음)는 메르센 트위스터 알고리즘보다 구현 속도가 더 빠릅니다. 주기는 2199371이고, 가능한 값은 구간 (0, 1) 내에 있는 252의 배수입니다. 이 생성기는 기본적으로 [1, 2)에 포함되는 배정밀도 값을 생성하고, 이러한 값은 U(0,1) 값을 생성하도록 변환됩니다. 이 생성기는 다중 스트림이나 서브스트림을 지원하지 않습니다.

mcg16807

승수 a=75, 모듈로 m=2311을 사용하는 32비트 승산식 합동법(Multiplicative Congruential) 생성기입니다([14]에 설명되어 있음). 이 생성기는 주기가 2312이며, 다중 스트림이나 서브스트림을 지원하지 않습니다. 각 U(0,1) 값은 생성기에서 단일 32비트 정수를 사용하여 생성됩니다. 가능한 값은 엄격하게 구간 (0, 1) 내에 있는 모든 (2311)1의 배수입니다. mcg16807 스트림의 경우 randn에서 사용되는 디폴트 알고리즘은 극좌표 알고리즘입니다([1]에 설명되어 있음).

참고

이 생성기는 MATLAB 버전 4부터 rand('seed',s)randn('seed',s)를 사용하여 활성화되는 rand 함수와 randn 함수에서 사용하는 생성기와 동일합니다.

mlfg6331_64

지연값(lags) l=63, k=31을 사용하는 64비트 시차 피보나치 수열(Multiplicative Lagged Fibonacci) 생성기입니다([10]에 설명되어 있음). 이 생성기는 SPRNG 라이브러리에 구현된 MLFG와 유사합니다. 이 생성기는 주기가 대략적으로 2124입니다. 또한, 파라미터화를 통해 최대 261개의 병렬 스트림을 지원하고, 각각 길이가 272251개의 서브스트림을 지원합니다. 각 U(0,1) 값은 생성기에서 64비트 정수 하나를 사용하여 생성됩니다. 가능한 값은 엄격하게 구간 (0, 1) 내에 있는 264의 모든 배수입니다. mlfg6331_64 스트림에 기본적으로 사용되는 randn 알고리즘은 지구라트 알고리즘 [7]이지만, 그 기반에는 mlfg6331_64 생성기가 있습니다.

mrg32k3a

32비트 결합 다중 재귀적(Combined Multiple Recursive) 생성기입니다([2]에 설명되어 있음). 이 생성기는 C로 작성된 RngStreams 패키지에 구현된 CMRG와 유사합니다. 이 생성기는 주기가 2191이며 수열 분할을 통해 각각 길이가 2127인 최대 263개의 병렬 스트림을 지원합니다. 또한 각각 길이가 276251개의 서브스트림도 지원합니다. 각 U(0,1) 값은 생성기에서 2개의 32비트 정수를 사용하여 생성됩니다. 가능한 값은 엄격하게 구간 (0, 1) 내에 있는 253의 배수입니다. 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) a=69069, 가수(Addend) b=1234567, 모듈로(Modulus) 232을 사용하여 선형 합동법 생성기로 계산된, 마르사글리아(Marsaglia)의 SHR3 시프트 레지스터 생성기입니다. SHR3은 u=u(I+L13)(I+R17)(I+L5)으로 정의되는 3 시프트 레지스터 생성기입니다. 여기서 I는 단위 연산자이고, L은 왼쪽 시프트 연산자이며, R은 오른쪽 시프트 연산자입니다. 결합 생성기(SHR3 부분은 [7]에 설명되어 있음)는 주기가 대략적으로 264입니다. 이 생성기는 다중 스트림이나 서브스트림을 지원하지 않습니다. 각 U(0,1) 값은 생성기에서 32비트 정수 하나를 사용하여 생성됩니다. 가능한 값은 엄격하게 구간 (0, 1) 내에 있는 232의 모든 배수입니다. shr3cong 스트림에 기본적으로 사용되는 randn 알고리즘은 이전 형식의 지구라트 알고리즘 [9]이지만, 그 기반에는 shr3cong 생성기가 있습니다. 이 생성기는 MATLAB 버전 5부터 randn('state',s)를 사용하여 활성화되는 randn 함수에서 사용하는 생성기와 동일합니다.

참고

[6](1999년)에 사용된 SHR3 생성기는 [7](2000년)에 사용된 것과 다릅니다. MATLAB에서는 [7]에 나와 있는 가장 최신 버전의 생성기를 사용합니다.

swb2712

수정된 자리 내림을 사용하는 뺄셈(Subtract-with-Borrow) 생성기입니다([8]에 설명되어 있음). 이 생성기는 지연값(lags) 27과 12를 사용하는 가산식 시차 피보나치(Additive Lagged Fibonacci) 생성기와 유사하지만, 대략적으로 21492의 더 긴 주기를 갖도록 변형되었습니다. 이 생성기는 기본적으로 배정밀도로 동작하여 U(0,1) 값을 만들고, 열린 구간 (0, 1) 내에 있는 모든 값이 가능합니다. swb2712 스트림에 기본적으로 사용되는 randn 알고리즘은 지구라트 알고리즘 [7]이지만, 그 기반에는 swb2712 생성기가 있습니다.

참고

이 생성기는 MATLAB 버전 5부터 rand('state',s)를 사용하여 활성화되는 rand 함수에서 사용하는 생성기와 동일합니다.

변환 알고리즘

Inversion

표준 정규 역누적 분포 함수(Standard Normal Inverse Cumulative Distribution Function)를 균일 확률 변량에 적용하여 정규 확률 변량을 계산합니다. 정규 값당 정확히 하나의 균일 값이 사용됩니다.

Polar

극값 거부 알고리즘(Polar Rejection Algorithm)입니다([1]에 설명되어 있음). 평균적으로 정규 값당 대략 1.27개의 균일 값이 사용됩니다.

Ziggurat

지구라트 알고리즘입니다([7]에 설명되어 있음). 평균적으로 정규 값당 대략 2.02개의 균일 값이 사용됩니다.

스트림 구성하기

난수 스트림 s에는 s의 동작을 제어하는 속성이 있습니다. 속성에 액세스하거나 속성을 변경하려면 구문 p = s.Propertys.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.

참고 항목

|

관련 항목