UFO ET IT

의사 난수 생성기-지수 분포

ufoet 2020. 12. 15. 19:33
반응형

의사 난수 생성기-지수 분포


나는 의사 난수를 생성하고 싶다. 지금까지 나는 .Net 라이브러리의 Random.Next(int min, int max)기능 에 매우 만족했다 . 이 다양한 PRNG도이되는 가정 사용되는 균일 한 분포를 ,하지만 난 아주 많이 좋아는 사용하여 몇 가지 숫자를 생성하는 것 지수 분포를 .

의사 코드 나 C ++, Java 등을 허용하지만 C #으로 프로그래밍하고 있습니다.

제안 / 코드 스 니펫 / 알고리즘 / 생각?


균일 난수 생성기에 액세스 할 수 있으므로 CDF를 알고있는 다른 분포와 함께 분포 된 난수를 생성하는 것은 반전 방법을 사용하면 쉽습니다 .

따라서, 균일 한 난수를 생성 u,에 [0,1), 다음 계산 x에 의해 :

x = log(1-u)/(−λ ),

여기서 λ는 지수 분포의 비율 매개 변수입니다. 이제 x지수 분포를 가진 난수입니다. 참고 있다는 log것입니다 위 ln, 자연 로그.


표본 추출의 기본 정리는 원하는 분포를 정규화, 통합 및 반전 할 수 있다면 집에서 자유 롭다고 주장합니다.

원하는 분포 F(x)[a,b]. 당신은 계산

C(y) = \int_a^y F(x) dx

그것을 얻기 위해 반전하고 C^{-1}, z[0,1)에 균일하게 던지고

x_i = C^{-1}(z_i)

원하는 분포를 갖게됩니다.


귀하의 경우 : F(x) = ke^{-kx}그리고 나는 당신이 [0,infinity]. 우리는 :

C(y) = 1 - e^{-ky}

뒤집을 수있는

x = -1/k  ln(1 - z)

z에 대해 [0,1).


그러나 솔직히 잘 디버깅 된 라이브러리를 사용하는 것이 자신의 수정을 위해이 작업을 수행하지 않는 한 더 똑똑합니다.


좋은 난수를 원한다면 gsl 루틴 ( http://www.gnu.org/software/gsl/)에 연결하는 것을 고려 하십시오 . 그들에게는 루틴이 gsl_ran_exponential있습니다. [0, 1)에 균일 분포가있는 내장 생성기를 사용하여 난수를 생성하려면 (예 : u = Random.Next (0, N-1) / N, 일부 큰 N) 다음을 사용하십시오.

-mu * log (1-u)

gsl 소스에서 randist / exponential.c를 참조하십시오.

편집 : 일부 나중에 답변과 비교하기 위해-이것은 mu = 1 / lambda와 동일합니다. 여기서 mu는 OP가 연결된 wikipedia 페이지에서 scale 매개 변수라고도하는 분포의 평균이고, lambda는 비율 매개 변수입니다.


지수 분포의 한 가지 흥미로운 속성 : 지수 간 도착 시간이있는 도착 프로세스를 고려하십시오. 임의의 기간 (t1, t2)과 해당 기간의 도착을 취하십시오. 이러한 도착은 t1과 t2 사이에 균일하게 분배됩니다. (Sheldon Ross, 확률 적 과정).

의사 난수 생성기가 있고 어떤 이유로 (예 : 내 소프트웨어가 로그를 계산할 수 없음) 위의 변환을 원하지 않는 경우 평균 1.0의 지수 rv를 원합니다.

다음을 수행 할 수 있습니다.

1) 1001 U (0,1) 확률 변수를 만듭니다.

2) 순서대로 정렬

3) 첫 번째에서 두 번째를 빼고 두 번째에서 세 번째를 빼서 1000 개의 차이를 얻습니다.

4) 이러한 차이는 평균이 1.0 인 분포의 지수 RV입니다.

덜 효율적이라고 생각하지만 같은 목적을위한 수단입니다.


Dan Dyer 의 오픈 소스 Uncommons Maths 라이브러리 는 Java에 대한 난수 생성기, 확률 분포, 조합 및 통계를 제공합니다.

다른 귀중한 클래스 중에서 ExponentialGenerator는 @Alok Singhal이 설명하는 아이디어를 본질적으로 구현했습니다. 에서 의 튜토리얼 블로그 , 코드 조각은 평균 10 회 분에 일어난 어떤 임의의 이벤트를 시뮬레이션하기 위해 주어진다 :

final long oneMinute = 60000;
Random rng = new MersenneTwisterRNG();

// Generate events at an average rate of 10 per minute.
ExponentialGenerator gen = new ExponentialGenerator(10, rng);
boolean running = true;
while (true)
{
    long interval = Math.round(gen.nextValue() * oneMinute);
    Thread.sleep(interval);

    // Fire event here.
}

물론 시간 단위 per second( a minute여기 대신) 를 선호하는 경우 final long oneMinute = 1000.

에 깊은 간다 소스 코드 방법의 nextValue()ExponentialGenerator, 당신은 소위 찾을 수 역 시료 채취 변환 에 설명 Generating_exponential_variates [위키]를 :

public Double nextValue()
{
    double u;
    do
    {
        // Get a uniformly-distributed random double between
        // zero (inclusive) and 1 (exclusive)
        u = rng.nextDouble();
    } while (u == 0d); // Reject zero, u must be positive for this to work.
    return (-Math.log(u)) / rate.nextValue();
}  

P.S.: Recently I am using the Uncommons Maths library. Thanks Dan Dyer.


If I understand your problem, and you can accept a finite number of PRNG's, you could follow an approach like:

  • Create an array where every element is in your exponential distribution
  • Generate a PRNG which is an integer index into the array. Return the element in the array at that index.

This was what I used when faced with similar requirements:

// sorry.. pseudocode, mine was in Tcl:

int weighted_random (int max) {
    float random_number = rand();
    return floor(max - ceil( max * random_number * random_number))
}

Of course this is the formula of squaring the random number so you're generating a random number along a quadratic curve.

ReferenceURL : https://stackoverflow.com/questions/2106503/pseudorandom-number-generator-exponential-distribution

반응형