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