11

I am trying to generate exponentially distributed random number with mean equal to 1. I know how to get random number for normal distribution with mean and standard deviation. We can get it by normal(mean, standard_deviation), but I don't know how to get random number for exponential distribution.

Can anyone help me with this?

Filip Roséen - refp
  • 62,493
  • 20
  • 150
  • 196
Sadiksha Gautam
  • 5,032
  • 6
  • 40
  • 71
  • I basic example is found [here](http://www.cplusplus.com/reference/std/random/exponential_distribution/). I haven't checked if it really works, though. – jogojapan Jul 15 '12 at 11:31
  • Wikipedia's page contains a method, if you have a source of uniform random numbers: http://en.wikipedia.org/wiki/Exponential_distribution#Generating_exponential_variates –  Jul 15 '12 at 11:32

2 Answers2

13

With C++11 the standard actually guarantees that there is a RNG following the requirements of exponential-distribution available in the STL, and fittingly the object-type has a very descriptive name.

The mean in an exponentially distributed random generator is calculated by the formula E[X] = 1 / lambda1.

std::exponential_distribution has a constructor taking lambda as an argument, so we can easily create an object following your rules by calculating the value of lambda and passing this to our generator.

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

Footnotes
1. according to en.wikipedia.org - Exponential distribution > Mean, variance, moments and median


Distribution as readable ascii chart

#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 -> 

Filip Roséen - refp
  • 62,493
  • 20
  • 150
  • 196
  • Could you explain this line : `std::mt19937 rnd_gen (rd ());` and this one: `rng (rnd_gen)`? Why do you need this `mt19937` thing once you have the exponential_distribution? – bobroxsox Mar 20 '14 at 08:31
  • 1
    @bobroxsox `rnd_gen` is the *generator* used to spit out a steady stream of numbers, `rng` is the *distribution object* responsible for adjusting the numbers yield by `rnd_gen` to follow a certain distribution. – Filip Roséen - refp Mar 20 '14 at 08:36
10

Generating an exponential distribution random variable can be done by:

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

More information can be found in this wikipedia article

In exponential distribution: lamda = 1/mean, so it gets you:

myVar = -ln(U) * mean (where U~Uniform(0,1)). 
amit
  • 175,853
  • 27
  • 231
  • 333
  • 2
    You want U in `(0,1)` rather than `[0,1]` in practice, because a real RNG is discrete, not continuous. You don't really want to get the result `1` from the uniform RNG (and hence produce 0 in your "exponential distribution"), and you *really* don't want `0` from the uniform RNG. – Steve Jessop Jul 15 '12 at 11:38
  • 2
    @SteveJessop: Thanks for the correction, since we are not dealing with real continious distribution, but merely simulating one with discrete values - you are absolutely correct. – amit Jul 15 '12 at 11:41
  • @Steve: Disagree. `+0` or `+infinity` are perfectly reasonable outputs from a floating-point approximation to a sample from an exponential distribution. How to handle overflow and underflow (and other extreme samples) come from actually analyzing the needs of the application, rather than a philosophical aversion to degeneracy and other edge conditions. –  Jul 15 '12 at 18:31
  • 1
    @Hurkyl: `log(0)` doesn't return `-infinity`, it returns `-HUGE_VAL`, which means that this function would return `+HUGE_VAL * mean`. When `mean` is 1 I suppose the caller could handle this, but IMO it's not that great an edge case for the caller to deal with when `mean < 1`. That said, if `U` really is a uniform double on `[0,1]` then it only happens about 1 in 2^53, so most callers don't need to handle it. Whether it's included or not doesn't skew the distribution all that much. – Steve Jessop Jul 16 '12 at 09:57
  • For the `0` case it might be better to return `DBL_MIN`, and let the caller worry about losing the precision of that when they use it. Being positive is a well-known property of an exponential distribution, and if your approximation is going to lose that then it should at the very least document it loudly so that callers know not to e.g. divide by it. If `0` is reasonable, then why not small negative values: it's "just an approximation"? I think either would confuse callers. I may be wrong. – Steve Jessop Jul 16 '12 at 10:00
  • @Steve: Your last question is an easy one: `0` is a better approximation than a negative number. Upon reflection, "discretization" is a better word choice. Note these issues can be made more significant with very small or large means, if done in single precision, or when the underlying integer RNG has a small range. `DBL_MIN` may well be a good choice for underflow -- my point is just that the handling of extreme cases in this (or any) function should be done intelligently based on its purpose, rather than just artificially truncating the range of values so you can ignore them. –  Jul 16 '12 at 14:50
  • 2
    @user4786271 No, this is an algorithmic explanation of how to do it. Should be fairly easy to implement in any language – amit May 14 '15 at 20:18