Main Content

난수 생성 제어

이 예제에서는 rng 함수를 사용하여 난수 생성을 제어하는 방법을 보여줍니다.

MATLAB®에서 (의사) 난수는 rand 함수, randi 함수, randn 함수로 생성합니다. 다른 많은 함수가 이 세 함수를 호출하는데, 이 세 함수는 기본적인 구성요소입니다. 이 세 함수는 모두 rng를 사용하여 제어할 수 있는 하나의 공유 난수 생성기에 종속됩니다.

참고로, MATLAB에서 "난수"는 전혀 예측할 수 없는 수는 아니며, 결정론적 알고리즘(Deterministic Algorithm)에 의해 생성된다는 점에 유의해야 합니다. 이 알고리즘은 알고리즘을 모르는 사람들에게는 해당 출력값이 독립적인 랜덤 시퀀스인 것처럼 보이도록 매우 복잡하게 설계되었으며, 다양한 통계적 임의성 검정을 통과하였습니다. 여기에서 소개하는 함수를 사용하면 결정론의 장점을 활용하여 다음을 수행할 수 있습니다.

  • 난수를 포함하는 계산을 반복하고 동일한 결과를 얻을 수 있음

  • 반복된 계산을 수행할 때 매번 다른 난수를 사용한다는 점이 보장됨

또한 개별적인 계산 결과의 조합이 바른지 증명하는 데, 명백한 임의성의 장점을 활용할 수도 있습니다.

"다시 시작하기"

MATLAB을 다시 시작해 새로운 MATLAB 세션에서 rand, randi, randn 중 하나의 함수를 실행시켜 출력값을 확인해 보면 일련의 숫자가 MATLAB 재시작과 함께 동일하게 다시 반환되는 것을 알 수 있습니다. 그런데 MATLAB을 실제로 다시 시작하지 않고 난수 생성기의 상태를 바꾸어 난수 생성을 처음부터 다시 시작하도록 설정할 수 있습니다. 이러한 기능은 난수가 포함된 계산을 반복하고 동일한 결과를 얻으려는 경우 유용할 수 있습니다.

처음 MATLAB 세션을 시작하거나 rng("default")를 호출하면 MATLAB은 디폴트 알고리즘과 시드값을 사용해서 난수 생성기를 초기화합니다. R2023b부터는 MATLAB 기본 설정에서 디폴트 알고리즘과 시드값을 설정할 수 있습니다. 이 기본 설정을 변경하지 않으면 rng는 이전 릴리스에서처럼 공장 출하값 "twister"(시드값이 0인 메르센 트위스터 생성기)를 사용합니다. 자세한 내용은 난수 생성기의 디폴트 설정난수 생성기의 재현성 항목을 참조하십시오.

rng("default")를 사용하면 매우 간단한 방법으로 난수 생성기를 디폴트 설정으로 되돌릴 수 있습니다.

rng("default")
rand % returns the same value as at startup
ans = 0.8147

MATLAB 시작 시 난수의 "디폴트" 설정은 무엇이며, rng("default")는 어떤 기능을 할까요? R2023b 이전 릴리스에서 입력값 없이 rng를 호출하면 생성기 알고리즘은 메르센 트위스터이며 시드값은 0임을 알 수 있습니다.

rng
ans = struct with fields:
     Type: 'twister'
     Seed: 0
    State: [625x1 uint32]

아래에서는 State 필드를 포함한 위의 출력값을 사용하여, MATLAB에서 난수가 생성되는 방식을 제어하고 변경하는 방법을 자세히 살펴보겠습니다. 여기서는 우선, 위의 출력값을 통해 현재 어떤 종류의 생성기가 rand, randi, randn에 사용되는지 알 수 있습니다.

비반복성

rand, randi, randn 중 하나를 호출할 때마다 이 함수들은 공유하는 난수 생성기에서 새 값을 가져옵니다. 연속된 새 값들은 통계적으로 독립이라 할 수 있습니다. 그러나 위에서 언급했듯이 이 함수들은 MATLAB을 다시 시작할 때마다 초기화되고 동일한 숫자를 반환합니다. 분명히 말해, 동일한 "난수"를 사용하는 계산은 통계적으로 독립이라 할 수 없습니다. 따라서 둘 이상의 MATLAB 세션에서 수행된 계산을 통계적으로 독립된 것처럼 결합해야 할 경우에는 생성기 설정을 디폴트로 설정해서는 안 됩니다.

새 MATLAB 세션에서 동일한 난수가 반복되지 않도록 하는 한 가지 간단한 방법은 난수 생성기에 대해 다른 시드값을 선택하는 것입니다. 이를 간단히 수행하려면 rng를 사용하여 현재 시간을 기반으로 시드값을 만들면 됩니다.

rng("shuffle")
rand
ans = 0.3146

"shuffle"을 사용할 때마다 생성기의 시드값이 다르게 지정됩니다. 입력값 없이 rng를 호출하면 실제로 사용된 시드값을 확인할 수 있습니다.

rng
ans = struct with fields:
     Type: 'twister'
     Seed: 736106447
    State: [625x1 uint32]

rng("shuffle") % creates a different seed each time
rng
ans = struct with fields:
     Type: 'twister'
     Seed: 736106457
    State: [625x1 uint32]

rand
ans = 0.8198

"shuffle"을 사용하면 난수 생성기의 시드값을 간단하게 다시 지정할 수 있습니다. MATLAB에서 "진정한" 임의성을 얻기 위해 'shuffle'을 사용하는 것이 편리하고 유용한 방법이라고 생각할 수도 있습니다. 그러나 대부분의 경우 "shuffle"은 전혀 사용할 필요가 없습니다. 현재 시간을 기반으로 시드값을 선택하면 rand, randi, randn에서 얻는 값의 통계적 속성이 향상되지 않으며, 실제로 이러한 값의 "임의성이 더 높아지지도" 않습니다. MATLAB을 시작할 때마다 생성기의 시드값을 다시 지정하거나, 난수를 포함하는 일부 대규모 계산을 실행하기 전에 생성기의 시드값을 다시 지정하는 것은 괜찮지만, 한 세션 내에서 너무 자주 생성기의 시드값을 다시 시정하면 난수의 통계적 속성에 영향을 미칠 수 있으므로 실제로는 좋지 않습니다.

"shuffle"을 사용하여 얻게 되는 효과는 일련의 값이 동일하게 반복되지 않도록 하는 것뿐입니다. 이 기능은 때때로 중요하거나 도움이 되기도 하지만 대개의 경우 전혀 중요하지 않습니다. "shuffle"을 사용할 경우, 나중에 계산을 반복할 수 있도록 rng가 생성한 시드값을 저장해야 할 수도 있음에 유의해야 합니다. 이 방법에 대해서는 아래에서 살펴보겠습니다.

반복성과 비반복성에 대한 세부적인 제어

지금까지는 난수 생성기를 디폴트 설정으로 재설정하고 현재 시간에 따라 생성된 시드값으로 이 생성기의 시드값을 다시 지정하는 방법을 살펴보았습니다. 또한 rng를 사용하여 난수 생성기의 시드를 특정 시드값으로 다시 지정할 수 있음을 확인했습니다.

동일한 시드값을 여러 번 사용하여 같은 계산을 반복할 수 있습니다. 예를 들어, 다음 코드를 두 번 실행할 경우,

rng(1) % the seed is any non-negative integer < 2^32
x = randn(1,5)
x = 1×5

   -0.6490    1.1812   -0.7585   -1.1096   -0.8456

rng(1)
x = randn(1,5)
x = 1×5

   -0.6490    1.1812   -0.7585   -1.1096   -0.8456

... 정확히 동일한 결과를 얻게 됩니다. 이 작업이 필요한 상황의 예로는 x를 지운 후에 다시 만들어서, 이후에 이러한 특정 값으로 x에 종속된 계산의 결과를 다시 확인하려는 경우가 해당됩니다.

반면, 각기 다른 시드값을 선택하여 동일한 계산이 반복되지 않도록 해야 할 수도 있습니다. 예를 들어, 한 MATLAB 세션에서는 다음 코드를 실행하고,

rng(2)
x2 = sum(randn(50,1000),1); % 1000 trials of a random walk

다른 세션에서는 다음 코드를 실행하는 경우,

rng(3)
x3 = sum(randn(50,1000),1);

두 결과를 결합할 수 있으며, 이때 동일한 결과가 두 번 반복되지 않음을 분명하게 확인할 수 있습니다.

x = [x2 x3];

"shuffle"과 마찬가지로, MATLAB의 난수 생성기의 시드값을 다시 지정할 경우 이후의 rand, randi, randn의 모든 출력값에 영향을 미치므로 주의가 필요합니다. 반복성이나 고유성이 요구되는 경우를 제외하고, 일반적으로는 생성기 시드값을 다시 지정하지 않고 단순히 임의값을 생성하는 것이 좋습니다. 생성기 시드값을 다시 지정해야 할 경우에는 대개 명령줄이나 코드 내의 눈에 잘 띄는 지점에서 수행하는 것이 가장 좋습니다.

생성기 유형 선택

위에서 설명한 대로 난수 생성기 시드값을 다시 지정할 수 있을 뿐 아니라, 사용할 난수 생성기의 유형을 선택할 수도 있습니다. 생성기 유형마다 각기 다른 난수열을 생성합니다. 예를 들어 난수의 통계적 속성에 따라 특정 유형을 선택할 수도 있습니다. 또는 다른 유형의 디폴트 생성기를 사용한 이전 버전의 MATLAB에서 결과를 다시 산출해야 하는 상황이 발생할 수도 있습니다.

생성기 유형을 선택하는 또 다른 일반적인 이유로는 "임의"의 입력 데이터를 생성하는 유효성 검사 테스트를 작성할 때 테스트에서 예측 가능한 결과가 항상 동일하게 나오도록 하려는 경우를 들 수 있습니다. 입력 데이터를 만들기 전에 rng를 시드값과 함께 호출하면 난수 생성기의 시드값이 다시 지정됩니다. 그러나 특정한 이유로 인해 생성기 유형이 변경된다면 rand, randi, randn의 출력값은 해당 시드값으로 예상되는 값과 달라집니다. 따라서 100% 확실한 반복성을 얻기 위해 생성기 유형을 지정할 수도 있습니다.

예를 들어, 다음 명령을 사용할 경우

rng(0,"twister")

rand, randi, randn은 0으로 시드값을 지정한 후에 메르센 트위스터(Mersenne Twister) 생성기 알고리즘을 사용합니다.

다음과 같이 "combRecursive"를 사용하면

rng(0,"combRecursive")

결합 다중 재귀적(Combined Multiple Recursive) 생성기 알고리즘이 선택됩니다. 이 알고리즘은 메르센 트위스터 알고리즘에서 지원되지 않는 일부 병렬 기능을 지원합니다.

다음 명령을 사용하면

rng(0,"v4")

MATLAB 4.0에서 디폴트 값으로 사용된 생성기 알고리즘이 선택됩니다.

또한 다음 명령을 사용하여 난수 생성기를 디폴트 설정으로 되돌릴 수도 있습니다.

rng("default")

그러나 MATLAB 릴리스마다 디폴트 난수 생성기 설정이 바뀔 수 있으므로 장기적인 관점에서 보면 "default"를 사용하더라도 경우에 따라 예측 가능한 결과를 얻지 못할 수도 있습니다. "default"를 사용하면 난수 생성기를 간단히 초기화할 수 있지만, 예상한 것과 더 가까운 결과를 얻으려면 생성기 유형과 시드값을 지정하는 것이 좋습니다.

반면, 대화형 방식으로 작업을 수행하고 반복성이 요구되는 경우에는 시드값과 함께 rng를 호출하는 편이 더 간단하며 대부분의 경우 충분합니다.

난수 생성기 설정 저장과 복원

입력값 없이 rng를 호출하면 앞에서 이미 설명한 두 가지 정보, 즉 생성기 유형과 생성기에 마지막으로 지정된 시드값 정수를 포함하는 필드로 구성된 스칼라 구조체가 반환됩니다.

s = rng
s = struct with fields:
     Type: 'twister'
     Seed: 0
    State: [625x1 uint32]

세 번째 필드인 State에는 생성기의 현재 상태 벡터 복사본이 포함됩니다. 이 상태 벡터는 생성기가 난수열에서 다음 값을 생성하기 위해 내부적으로 유지하는 정보입니다. rand, randi, randn 중 하나를 호출할 때마다 이 함수들이 공유하는 생성기의 내부 상태가 업데이트됩니다. 따라서 rng에서 반환한 설정 정보를 나타내는 구조체의 상태 벡터에는 상태가 캡처된 시점부터 일련의 난수를 반복하는 데 필요한 정보가 포함되어 있습니다.

이 출력값을 통해 정보를 얻을 수 있는 반면, rng는 설정 정보를 나타내는 구조체도 입력값으로 받으므로 상태 벡터를 포함해 해당 설정을 저장한 후 나중에 복원하여 계산을 반복할 수 있습니다. 설정에 생성기 유형을 포함시키면 나중에 얻을 결과를 예측할 수 있습니다. 여기서 "나중에"라는 표현은 현재 MATLAB 세션을 기준으로 바로 다음 순간부터 몇 년 후(여러 MATLAB 릴리스에 걸쳐)에 이르기까지 다양한 기간을 의미할 수 있습니다. 즉, 난수열에서 생성기 설정을 저장한 시점부터 언제든지 결과를 반복할 수 있습니다. 예를 들면 다음과 같습니다.

x1 = randn(10,10); % move ahead in the random number sequence
s = rng;           % save the settings at this point
x2 = randn(1,5)
x2 = 1×5

    0.8404   -0.8880    0.1001   -0.5445    0.3035

x3 = randn(5,5);   % move ahead in the random number sequence
rng(s);            % return the generator back to the saved state
x2 = randn(1,5)    % repeat the same numbers
x2 = 1×5

    0.8404   -0.8880    0.1001   -0.5445    0.3035

시드값을 다시 설정하면 엉성하게 초기화되지만, 설정 정보를 나타내는 구조체를 사용하여 생성기 상태를 저장한 후 복원하면 난수열의 어느 부분이든 반복할 수 있습니다.

설정 정보를 나타내는 구조체는 생성기 상태를 복원하는 데 가장 일반적으로 사용됩니다. 그러나 구조체에는 상태뿐 아니라 생성기 유형과 시드값도 포함되어 있으므로 생성기 유형을 일시적으로 전환하는 데에도 편리하게 사용할 수 있습니다. 예를 들어, MATLAB 5.0의 레거시 생성기 중 하나로 값을 생성해야 할 경우 현재 설정을 저장하는 동시에 이전 생성기를 사용하도록 전환할 수 있습니다.

previousSettings = rng(0,"v5uniform")
previousSettings = struct with fields:
     Type: 'twister'
     Seed: 0
    State: [625x1 uint32]

그런 다음 나중에 원래 설정을 복원할 수 있습니다.

rng(previousSettings)

설정값을 보여주는 구조체에 있는 필드 내용은 수정해서는 안 됩니다. 특히, 상태 벡터를 직접 생성해서는 안 되며, 생성기 상태에 종속되도록 형식을 구성해서도 안 됩니다.

더 간단하고 유연한 코드 작성

rng를 사용하면 난수 생성기 유형을 몰라도 다음을 수행할 수 있습니다.

  • 난수 생성기 시드값 다시 지정

  • 난수 생성기 설정 저장 후 복원

또한 난수 생성기의 디폴트 설정을 모르는 상태에서 난수 생성기를 디폴트 설정으로 되돌릴 수 있습니다. 상황에 따라 생성기 유형을 지정하고자 하는 경우가 있을 수 있는데 rng를 사용하면 생성기 유형을 지정할 필요가 없습니다.

이처럼 생성기 유형을 지정하는 과정을 건너뛸 수 있게 되면, 코드는 다른 생성기를 사용해야 하는 상황에 자동으로 적응되고 새 디폴트 난수 생성기 유형의 향상된 속성을 자동으로 활용합니다.

rngRandStream

MATLAB에서 rng를 사용하면 가장 일반적인 요건에 맞는 난수를 생성하여 편리하게 제어할 수 있습니다. 그러나 여러 개의 난수 스트림과 병렬 난수 생성이 포함된 더 복잡한 상황에서는 그에 적합한 더욱 복잡한 툴이 필요합니다. RandStream 클래스는 이러한 상황에 적합한 툴이며, 이 클래스를 사용하면 난수 생성을 가장 효과적으로 제어할 수 있습니다. 이 두 가지 툴은 상호 보완적으로 활용할 수 있습니다. RandStream의 유연성이 기반이 되면 rng는 훨씬 더 단순하고 간결한 구문을 제공합니다.