Home > Net >  How is it possible to get a random number with a specific probability?
How is it possible to get a random number with a specific probability?

Time:03-25

I wanted to make a random number picker in the range 1-50000.

But I want to do it so that the larger the number, the smaller the probability.

Probability like (1/2*number) or something else.

Can anybody help?

CodePudding user response:

You need a mapping function of some sort. What you get from Random is a few 'primitive' constructs that you can trust do exactly what their javadoc spec says they do:

  • .nextInt(X) which returns, uniform random (i.e. the probability chart is an exact horizontal line), a randomly chosen number between 0 and X-1 inclusive.
  • .nextBoolean() which gives you 1 bit of randomness.
  • .nextDouble(), giving you a mostly uniform random number between 0.0 and 1.0
  • nextGaussian() which gives you a random number whose probability chart is a uniform normal curve with standard deviation = 1.0 and midpoint (average) of 0.0.

For the double-returning methods, you run into some trouble if you want exact precision. Computers aren't magical. As a consequence, if you e.g. write this mapping function to turn nextDouble() into a standard uniformly distributed 6-sided die roll, you'd think: int dieRoll = 1 (int) (rnd.nextDouble() * 6); would do it. Had double been perfect, you'd be right. But they aren't, so, instead, best case scenario, 4 of 6 die faces are going to come up 750599937895083 times, and the other 2 die faces are going to come up 750599937895082 times. It'll be hard to really notice that, but it is provably imperfect. I assume this kind of tiny deviation doesn't matter to you, but, it's good to be aware that anytime you so much as mention double, inherent tiny errors creep into everything and you can't really stop that from happening.

What you need is some sort of mapping function that takes any amount of such randomly provided data (from those 3 primitives, and really only from nextInt/nextBoolean if you want to avoid the errors that double inherently brings) to produce what you want.

For example, imagine instead the 'primitive' I gave you is a uniform random value between 1 and 6, inclusive, i.e.: A standard 6-sided die roll. And I ask you to come up with a uniform algorithm (as in, each value is equally likely) to produce a number between 2 and 12, inclusive.

Perhaps you might think: Easy, just roll 2 dice and add em up. But that would be incorrect: 7 is far more likely than 12.

Instead, you'd roll 1 die and just register if it was even or odd. Then you roll the second die and that's your result, unless the first die was odd in which case you add 6 to it. If you get odd on the first die and 1 on the second die, you start the process over again; eventually you're bound to not roll snake eyes.

That'd be uniform random.

You can apply the same principle to your question. You need a mathematical function that maps the 'horizontal line' of .nextInt() to whatever curve you want. For example, sounds like you want to perhaps generate something and then take the square root and round it down, maybe. You're going to have to draw out or write a formula that precisely describes the probability density.

Here's an example:

while (true) {
  int v = (int) (50000.0 * Math.abs(r.nextGaussian()));
  if (v >= 1 && v <= 50000) return v;
}

That returns you a roughly normally distributed value, 1 being the most likely, 50000 being the least likely.

CodePudding user response:

One simple formula that will give you a very close approximation to what you want is

Random random = new Random();
int result = (int) Math.pow( 50001, random.nextDouble());

That will give a result in the range 1 - 50000, where the probability of each result is approximately proportional to 1 / result, which is what you asked for.

The reason why it works is that the probability of result being any value n within the range is P( n <= 50001^x < n 1) where x is randomly distributed in [0,1). That's the probability that x falls between log(n) and log(n 1), where the logs are base 50001. But that probability is proportional to log (1 1/n), which is very close to 1/n.

  • Related