伪随机数发生器 – 指数分布
我想生成一些伪随机数,直到现在我已经非常满意.Net库的Random.Next(int min, int max)
函数。 这个品种的PRNGs 应该是使用均匀分布 ,但是我非常想用一个指数分布生成一些数字。
我在C#编程,虽然我会接受伪代码或C ++,Java或类似的。
任何build议/代码片段/algorithm/想法?
由于您可以访问一个统一的随机数发生器,因此使用反演方法可以生成一个随其他发行版分布的随机数。
所以,在[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
并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)) }
当然这是平方随机数的公式,所以你可以沿着二次曲线产生一个随机数。