いくつかの擬似乱数を生成したいと思います。これまでは、.NetライブラリのRandom.Next(int min, int max)
関数に非常に満足しています。この種類のPRNGは、均一分布 を使用することを想定していますが、 指数分布 。
私はC#でプログラミングしていますが、擬似コードまたはC++、Javaなどを受け入れます。
提案/コードスニペット/アルゴリズム/考えはありますか?
一様な乱数ジェネレーターにアクセスできるため、CDFがわかっている他のディストリビューションで配布される乱数の生成は、 inversion method を使用すると簡単です。
したがって、_[0,1)
_で一様な乱数u
を生成し、次にx
を計算します:
x = log(1-u)/(
−λ_)
_、
ここで、λは指数分布のレートパラメーターです。現在、x
は指数分布の乱数です。上記のlog
はln
(自然対数)であることに注意してください。
サンプリングの基本定理は、希望する分布を正規化し、統合し、反転させることができれば、自由に使えると考えています。
F(x)
が_[a,b]
_で正規化された望ましい分布がある場合。計算する
_C(y) = \int_a^y F(x) dx
_
それを反転して_C^{-1}
_を取得し、[0,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)
_
for 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がリンクされているウィキペディアページのスケールパラメーターとも呼ばれ、ラムダはレートパラメーターです。
指数分布の興味深い特性の1つは、指数到着間隔の到着プロセスを検討することです。任意の期間(t1、t2)およびその期間に到着します。これらの到着は、t1とt2の間に均一に配信されます。 (シェルドン・ロス、確率過程)。
擬似乱数ジェネレーターがあり、何らかの理由で(たとえば、ソフトウェアがログを計算できない)、上記の変換を行いたくないが、指数関数r.vが必要な場合。平均が1.0です。
あなたはできる :
1)1001 U(0,1)のランダム変数を作成します。
2)順番に並べ替え
3)1番目から2番目を減算し、2番目から3番目を減算します。
4)これらの差は、平均= 1.0の分布からの指数RVです。
あまり効率的ではないと思いますが、同じ目的のための手段です。
オープンソース 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
_を設定するだけです。
ExponentialGenerator
のメソッドnextValue()
の- ソースコード をさらに深く掘り下げると、いわゆる逆変換サンプリングGenerating_exponential_variates [wiki] で説明されています:
_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.:最近、Uncommons Mathsライブラリを使用しています。ダンダイアーに感謝します。
私があなたの問題を理解し、PRNGの有限数を受け入れることができる場合、次のようなアプローチに従うことができます: