如何生成具有指数分布(带均值)的随机数?

11

我想生成平均数为1的指数分布随机数。我知道如何获得具有平均值和标准差的正态分布随机数,可以使用 normal(mean, standard_deviation) 来获得,但我不知道如何获取指数分布的随机数。

谁能帮我解决这个问题?


基本示例在这里找到。虽然我还没有检查它是否真正有效。 - jogojapan
维基百科的页面包含一个方法,如果您有均匀随机数的源:http://en.wikipedia.org/wiki/Exponential_distribution#Generating_exponential_variates - user1084944
2个回答

13

C++11 中,标准确保了 STL 中有一个符合指数分布要求的 RNG (随机数生成器),对应的 对象类型 也名字非常描述性。

在指数分布的随机数生成器中,均值 的计算公式为 E[X] = 1 / lambda1

std::exponential_distribution 类型有一个以 lambda 作为参数的构造函数,因此我们可以通过计算 lambda 的值并将其传递给生成器来轻松创建遵循您规则的对象。

std::exponential_distribution rng (1/1); // lambda = 1 / E[X]

脚注
1. 根据维基百科-指数分布>M均值,方差,矩和中位数


可读的ASCII图表展示分布

#include <iomanip>
#include <random>
#include <map>
#include <iostream>

int
main (int argc, char *argv[])
{
  double const exp_dist_mean   = 1;
  double const exp_dist_lambda = 1 / exp_dist_mean;

  std::random_device rd; 

  std::exponential_distribution<> rng (exp_dist_lambda);
  std::mt19937 rnd_gen (rd ());

  /* ... */

  std::map<int, int> result_set;

  for (int i =0; i < 100000; ++i)
    ++result_set[rng (rnd_gen) * 4]; 

  for (auto& v : result_set) {
    std::cout << std::setprecision (2) << std::fixed;

    std::cout << v.first/4.f << " - " << (v.first+1)/4.f << " -> ";
    std::cout << std::string (v.second/400, '.') << std::endl;

    if (v.second/400 == 0)
      break;
  }
}

0.00 - 0.25 -> ........................................................
0.25 - 0.50 -> ...........................................
0.50 - 0.75 -> .................................
0.75 - 1.00 -> .........................
1.00 - 1.25 -> ....................
1.25 - 1.50 -> ...............
1.50 - 1.75 -> ............
1.75 - 2.00 -> .........
2.00 - 2.25 -> .......
2.25 - 2.50 -> .....
2.50 - 2.75 -> ....
2.75 - 3.00 -> ...
3.00 - 3.25 -> ..
3.25 - 3.50 -> ..
3.50 - 3.75 -> .
3.75 - 4.00 -> .
4.00 - 4.25 -> .
4.25 - 4.50 -> 


你能解释一下这行代码吗:std::mt19937 rnd_gen (rd ()); 还有这行:rng (rnd_gen)?当你已经有指数分布时,为什么还需要 mt19937 - bobroxsox
1
@bobroxsox rnd_gen是用于产生持续数字流的生成器rng分布对象,它负责调整rnd_gen产生的数字以遵循特定的分布。 - Filip Roséen - refp
啊,这很有道理。谢谢! - bobroxsox

10

生成指数分布的随机变量可以通过以下方法实现:

-ln(U)/lambda (where U~Uniform(0,1)). 

这个维基百科文章提供了更多信息

在指数分布中:lambda = 1 / mean,因此可以得到:

myVar = -ln(U) * mean (where U~Uniform(0,1)). 

2
在实践中,您希望U在(0,1)而不是[0,1]中,因为真正的随机数生成器是离散的,而不是连续的。您真的不想从均匀分布的随机数生成器中得到结果1(从而在“指数分布”中产生0),而且您真的不想从均匀分布的随机数生成器中得到0 - Steve Jessop
2
@SteveJessop:感谢您的纠正,由于我们不涉及真正的连续分布,而仅仅是用离散值模拟一个分布 - 您是完全正确的。 - amit
1
@Hurkyl: log(0) 不会返回 -infinity,它会返回 -HUGE_VAL,这意味着该函数将返回 +HUGE_VAL * mean。当 mean 为1时,我认为调用者可能可以处理此问题,但是对于 mean <1 的情况处理起来并不容易。话虽如此,如果 U 真的是 [0,1] 上的均匀分布双精度数,则仅会发生约 2 ^ 53 中的1次,因此大多数调用者不需要处理它。无论是否包含此问题,都不会使分布偏移太多。 - Steve Jessop
对于0的情况,最好返回DBL_MIN,让调用者在使用时担心丢失精度。正数是指数分布的一个众所周知的特性,如果你的近似值会丢失这个特性,那么至少应该大声地记录下来,以便调用者知道不要例如除以它。如果0是合理的,那为什么不考虑小的负值呢:它只是一个“近似值”?我认为这两种情况都会让调用者感到困惑。我可能错了。 - Steve Jessop
2
@user4786271 不是,这只是一个如何实现的算法解释。在任何语言中都应该很容易实现。 - amit
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接