World's most popular travel blog for travel bloggers.

Non-uniform random distribution: How do I get a random between 100 and 180 that is on average close to 120? (like in a Gaussian distribution)

, , No Comments
Problem Detail: 

Presume I have the following case:

  • int value a
  • int value b, for which a < b
  • int value i, for which a <= i < b
  • I need an int value x, for which a <= x < b, randomly chosen, according to a non-uniform distribution: the distribution should follow a bell curve which is centered around i.

In Java, I have the following methods available on java.util.Random:

  • nextInt(int m): int between 0 and m
  • nextDouble(): double between 0.0 and 1.0
  • nextGaussian(): double between -Infinity and +Infinity, usually close to 0.0.

How do I build such a non-uniform distribution from these building blocks? How do I reliably and efficiently transform nextGaussian() into nextGaussian(a, b, i)? The part I am struggling with is to enforce that x is selected between a and b (without doing a trial-and-error).

Asked By : Geoffrey De Smet

Answered By : Mike Dunlavey

I would generate a beta distribution, and then expand to the desired range and round to the nearest integer.

A beta distribution on the 0-1 scale has two parameters: $Beta(a,b)$. $Beta(1,1)$ is simply a flat uniform. You want $a$ and $b$ to be > 1 or it won't have a central peak. The mean is $a/(a+b)$, and the mode (peak) is $(a-1)/(a+b-2)$.

The larger $a$ and $b$ are, the more "peaked" the distribution is.

Here's how to generate it from uniform random numbers if $a$ and $b$ are integers:

First, here's how you generate a Gamma variate $Gamma(1,a)$.

double Gamma1(int n){   double sum = 0;   for (int i = 0; i < n; i++){     sum += -log(getUniform());   }   return sum; } 

Then

double Beta(int a, int b){   double x = Gamma1(a);   double y = Gamma1(b);   return x/(x+y); } 

Then for your problem, you have a span from A to B with mode at I. Then the distance from A to I is fraction $(I-A)/(B-A)$, so that is the mode of the distribution. Then decide how large you want $a+b$ to be, the more the sharper. You might start with 10, call it $n$. Then calculate $$a = (I-A)/(B-A)*(n-2)+1$$ and use the nearest integer value for $a$, and of course $b=n-a$.

Then all you gotta do is calculate

A + (B-A)*Beta(a,b) 

and round to the nearest integer.

It sounds like your requirements are pretty flexible, so this should be good enough.

Anyway, look up Beta distribution.

EDIT: Another way that might be simpler: Use order statistics. Generate $n$ uniforms, sort them, and then choose the $a$th one, and scale that.

Best Answer from StackOverflow

Question Source : http://cs.stackexchange.com/questions/18467

0 comments:

Post a Comment

Let us know your responses and feedback