我想生成一些伪随机数,直到现在我一直非常满意.Net库的Random.Next(int min, int max)
函数。这个品种的PRNG 假设使用Uniform distribution,但我非常希望使用Exponential Distribution生成一些数字。
我正在用C#编程,虽然我会接受伪代码或C ++,Java等。
任何建议/代码片段/算法/想法?
答案 0 :(得分:96)
由于您可以访问统一的随机数生成器,因此使用inversion method可以轻松生成随您知道的CDF分发的随机数。
因此,在u
中生成一个统一的随机数[0,1)
,然后通过以下方式计算x
:
x = log(1-u)/(
- {λ{1}},
其中λ是指数分布的速率参数。现在,)
是一个具有指数分布的随机数。请注意,上面的x
是log
,即自然对数。
答案 1 :(得分:13)
采样的基本定理认为,如果你可以归一化,整合和反转所需的分布,你就可以免费回家了。
如果您在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)
for z在[0,1)
上统一抛出。
但是,坦率地说,使用经过良好调试的库比较聪明,除非你为自己的启发做这件事。
答案 2 :(得分:12)
这是我在维基百科上找到的公式:
T = -Ln(u) / λ
我们创建一个在 [0,1] 中具有均匀分布 (u) 的随机数,我们得到 x :
随机 R = new Random();
double u = R.NextDouble();
double x = -Math.Log(u)/(λ);
答案 3 :(得分:6)
如果您想要好的随机数,请考虑链接到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链接到的维基百科页面上的scale参数,lambda是rate参数。
答案 4 :(得分:4)
指数分布的一个有趣特性:考虑具有指数到达间隔时间的到达过程。在任何时间段(t1,t2)和该时期内的到达时间。这些到达者是在t1和t2之间分配的UNIFORMLY。 (Sheldon Ross,Stochastic Processes)。
如果我有一个伪随机数生成器,并且由于某种原因(例如我的软件无法计算日志)你不想进行上述转换,但想要一个指数r.v.平均值为1.0。
你可以:
1)创建1001个U(0,1)随机变量。
2)按顺序排序
3)从第一个减去第二个,从第二个减去第三个,......得到1000个差异。
4)这些差异是具有均值= 1.0的分布的指数RV。
我认为效率较低,但却是达到同样目的的手段。
答案 5 :(得分:1)
开源Uncommons Maths library by Dan Dyer为Java提供随机数生成器,概率分布,组合和统计。
在其他有价值的课程中,ExponentialGenerator
基本上实现了@Alok Singhal解释的想法。在its tutorial blog中,代码片段用于模拟平均每分钟发生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
的{{3}},您会发现{{3}中描述的所谓逆变换采样 }:
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库。谢谢Dan Dyer。
答案 6 :(得分:0)
如果我理解你的问题,并且你可以接受有限数量的PRNG,你可以遵循以下方法:
答案 7 :(得分:0)
还有另一种生成指数(rate
)随机数的方法,尽管它不像现在使用对数那样方便。它来自 John von Neumann (1951) 的算法,仅使用比较。
scale
为 1/rate
。将 highpart
设置为 0。scale
)随机数(如NextDouble()*scale
),称之为u
。val
设置为 u
,并将 accept
设置为 1。scale
)随机数,称之为v
。u
大于v
,将u
设置为v
,然后将accept
设置为1减去accept
,然后转到第 4 步。val + highpart
。scale
添加到 highpart
并转到第 2 步。参考:
答案 8 :(得分:-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))
}
当然,这是对随机数求平方的公式,因此您沿着二次曲线生成一个随机数。