65

いくつかの疑似乱数を生成したいのですが、今までは .Net ライブラリのRandom.Next(int min, int max)機能に非常に満足していました。この種の PRNG は一様分布を使用することになっていますが、指数分布を使用していくつかの数値を生成したいと考えています。

私は C# でプログラミングしていますが、疑似コードや C++、Java なども受け入れます。

提案/コードスニペット/アルゴリズム/考えはありますか?

4

9 に答える 9

112

一様乱数発生器にアクセスできるので、反転法を使用して CDF がわかっている他の分布で分布する乱数を簡単に生成できます。

したがって、 で一様乱数 を生成u[0,1)、次のように計算xします。

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

ここλで、 は指数分布のレート パラメーターです。さて、xは指数分布の乱数です。log上記はln、自然対数であることに注意してください。

于 2010-01-21T02:44:10.243 に答える
16

サンプリングの基本定理によれば、目的の分布を正規化、統合、反転できれば、ホーム フリーになります。

F(x)で正規化された目的の分布がある場合[a,b]。あなたが計算します

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

それを反転して取得し、 [0,1) に一様にC^{-1}投げて見つけます。z

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)


しかし、率直に言って、十分にデバッグされたライブラリを使用する方が賢明です。

于 2010-01-21T02:44:58.067 に答える
7

適切な乱数が必要な場合は、gslルーチンへのリンクを検討してください:http ://www.gnu.org/software/gsl/ 。彼らはルーチンを持っていgsl_ran_exponentialます。[0、1)に一様分布する組み込みジェネレーターを使用して乱数を生成する場合(たとえば、大きなNの場合はu = Random.Next(0、N-1)/ N)、次を使用します。

-mu * log (1-u)

gslソースのrandist/exponential.cを参照してください。

編集:後のいくつかの答えと比較するためだけに-これはmu = 1/lambdaと同等です。ここでのmuは分布の平均であり、OPがリンクされているウィキペディアページではスケールパラメーターとも呼ばれ、ラムダはレートパラメーターです。

于 2010-01-21T02:34:00.620 に答える
4

指数分布の 1 つの興味深い特性: 到着間隔が指数関数的である到着プロセスを考えてみましょう。任意の期間 (t1、t2) とその期間の到着を取得します。これらの到着は、t1 と t2 の間で均一に分散されます。(シェルドン・ロス、確率過程)。

疑似乱数ジェネレーターがあり、何らかの理由で (たとえば、ソフトウェアがログを計算できないなど)、上記の変換を実行したくないが、平均が 1.0 の指数 rv が必要な場合。

あなたはできる :

1) 1001 個の U(0,1) 確率変数を作成します。

2) 順番に並べ替える

3) 1 番目から 2 番目を引き、2 番目から 3 番目を引きます... 1000 の差を取得します。

4) これらの差は、平均 = 1.0 の分布からの指数 RV です。

効率は悪いと思いますが、同じ目的のための手段です。

于 2010-01-25T20:23:59.157 に答える
1

Dan Dyer によるオープンソースのUncommons Maths ライブラリは、Java 用の乱数ジェネレーター、確率分布、組み合わせ論、および統計を提供します。

他の貴重なクラスの中でもExponentialGenerator、@Alok Singhal によって説明されたアイデアを本質的に実装しています。そのチュートリアル ブログでは、1 分間に平均 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

のメソッドのソース コードをさらに詳しく調べると、 Generating_exponential_variates [wiki]で説明されている、いわゆる逆変換サンプリングが見つかります。nextValue()ExponentialGenerator

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();
}  

PS:最近、Uncommons Maths ライブラリを使用しています。ありがとうダン・ダイアー。

于 2014-06-26T12:12:58.250 に答える
0

私があなたの問題を理解していて、有限数のPRNGを受け入れることができる場合は、次のようなアプローチに従うことができます。

  • すべての要素が指数分布にある配列を作成します
  • 配列への整数インデックスであるPRNGを生成します。そのインデックスにある配列の要素を返します。
于 2010-01-21T02:30:28.890 に答える
-2

これは、同様の要件に直面したときに私が使用したものです。

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

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

もちろん、これは乱数を2乗する式なので、2次曲線に沿って乱数を生成します。

于 2010-01-21T02:31:17.210 に答える