How can I create a random integer n
in Java, between 1
and k
with a "linear descending distribution", i.e. 1
is most likely, 2
is less likely, 3
less likely, ..., k
least likely, and the probabilities descend linearly, like this:
I know that there are dosens of threads on this topic already, and I apologize for making a new one, but I can't seem to be able to create what I need from them. I know that using import java.util.*;
, the code
Random r=new Random();
int n=r.nextInt(k)+1;
creates a random integer between 1
and k
, distributed uniformly.
GENERALIZATION: Any hints for creating an arbitrarily distributed integer, i.e. f(n)=some function
, P(n)=f(n)/(f(1)+...+f(k))
), would also be appreciated, for example:
.
This should give you what you need:
Also, here is a general solution for POSITIVE functions (negative functions don't really make sense) along the range from start index to stopIndex:
Note: For functions that may return negative values, one method could be to take the absolute value of that function and apply it to the above solution for each yourFunction call.
There are lots of ways to do this, but probably the easiest is just to generate two random integers, one between
0
andk
, call itx
, one between0
andh
, call ity
. Ify > mx + b
(m
andb
chosen appropriately...) thenk-x
, elsex
.Edit: responding to comments up here so I can have a little more space.
Basically my solution exploits symmetry in your original distribution, where
p(x)
is a linear function ofx
. I responded before your edit about generalization, and this solution doesn't work in the general case (because there is no such symmetry in the general case).I imagined the problem like this:
k x h
, with a common hypotenuse. The composite shape is ak x h
rectangle.You'll have to take care of the edge cases also (I didn't bother). E.g. I see now that your distribution starts at 1, not 0, so there's an off-by-one in there, but it's easily fixed.
The first solution that comes to mind is to use a blocked-array. Each index would specify a range of values depending on how "probable" you want it to be. In this case, you would use a wider range for 1, less wider for 2, and so on until you reach a small value (lets say 1) for k.
Now the problem is just finding a random number, and then mapping that number to its bucket. you can do this for any distribution provided you can discretize the width of each interval. Let me know if i am missing something either in explaining the algorithm or its correctness. Needless to say, this needs to be optimized.
Something like this....