伪随机数发生器 – 指数分布

我想生成一些伪随机数,直到现在我已经非常满意.Net库的Random.Next(int min, int max)函数。 这个品种的PRNGs 应该是使用均匀分布 ,但是我非常想用一个指数分布生成一些数字。

我在C#编程,虽然我会接受伪代码或C ++,Java或类似的。

任何build议/代码片段/algorithm/想法?

由于您可以访问一个统一的随机数发生器,因此使用反演方法可以生成一个随其他发行版分布的随机数。

所以,在[0,1)生成一个统一的随机数u ,然后通过下式计算x

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

λ是指数分布的速率参数。 现在, x是具有指数分布的随机数。 请注意,上面的logln ,自然对数。

抽样的基本定理认为,如果你可以规范化,整合和反转所需的分布,你是免费的。

如果你有一个期望的分布F(x)[a,b]上规范化。 你计算

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

反转,得到C^{-1} ,在[0,1)上均匀抛出z并find

 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)上统一抛出。


但是,坦率地说,使用一个良好的debugging库是聪明的,除非你这样做是为了你自己的熏陶。

如果你想要很好的随机数,可以考虑链接到gsl例程: http ://www.gnu.org/software/gsl/。 他们有例行的gsl_ran_exponential 。 如果你想用一个内置的发生器在[0,1)上产生一个随机数(例如u = Random.Next(0,N-1)/ N),那么只要使用:

 -mu * log (1-u) 

请参阅gsl源文件中的randist / exponential.c。

编辑:只是为了比较一些后来的答案 – 这是相当于mu = 1 / lambda。 mu这里是分布的平均值,在OP链接到的wikipedia页面上也称为scale参数,而lambda是rate参数。

指数分布的一个有趣的性质:考虑具有指数到达间隔的到达过程。 采取任何一段时间(t1,t2)和那段时间的到来。 那些到达的是在t1和t2之间分配的UNIFORMLY。 (Sheldon Ross,随机过程)。

如果我有一个伪随机数生成器,并且出于某种原因(例如,我的软件无法计算日志),您不想进行上述转换,而是需要一个平均值为1.0的指数型rv。

您可以 :

1)创build1001个U(0,1)随机variables。

2)按顺序sorting

3)从第一个减去第二个,从第二个减去第二个,得到1000个差异。

4)这些差异是指数型RV与平均值= 1.0的分布。

我认为效率不高,而是达到同样目的的手段。

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

进一步深入到ExponentialGenerator方法nextValue()的源代码中,您将会在Generating_exponential_variates [wiki]中find所谓的逆变换采样

 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:最近我正在使用Uncommonsmath库。 谢谢Dan Dyer。

如果我了解您的问题,并且您可以接受有限数量的PRNG,则可以按照以下方法进行操作:

  • 创build一个数组,其中每个元素都处于指数分布
  • 生成一个PRNG,它是一个整数索引到数组中。 返回该索引处数组中的元素。

这是我在面对类似要求时所使用的:

 // sorry.. pseudocode, mine was in Tcl: int weighted_random (int max) { float random_number = rand(); return floor(max - ceil( max * random_number * random_number)) } 

当然这是平方随机数的公式,所以你可以沿着二次曲线产生一个随机数。

Interesting Posts