简体   繁体   中英

generate a random number between 1 and x where a lower number is more likely than a higher one

This is more of a maths/general programming question, but I am programming with PHP is that makes a difference.

I think the easiest way to explain is with an example.

If the range is between 1 and 10.

I want to generate a number that is between 1 an 10 but is more likely lower than high.

The only way I can think is generate an array with 10 elements equal to 1, 9 elements equal to 2, 8 elements equal to 3.....1 element equal to 10. Then generate a random number based on the number of elements.

The trouble is I am potentially dealing with 1 - 100000 and that array would be ridiculously big.

So how best to do it?

生成一个介于0和一个随机数之间的随机数!

Generate a number between 1 and foo(n), where foo runs an algorithm over n (eg a logarithmic function). Then reverse foo() on the result.

生成数字n ,该数字n0 <= n < 1 ,将其自身乘以x ,然后乘以x ,在其上求和并加1。

You could do

$rand = floor(100000 * (rand(0, 1)*rand(0, 1)));

Or something along these lines

There are basically two (or more?) ways to map uniform density to any distribution function: Inverse transformation sampling and Rejection sampling . I think in your case you should use the former.

快速简单:

rand(1, rand(1, n))

I think this may be what you're looking for :

Random by weight

What you need to do is generate a random number over a greater interval (preferably floating point), and map that into [1,10] in a nonuniform way. Exactly what way depends on how much more likely you want a 1 to be than a 9 or 10.

For C language solutions, see these libraries . You may find use for this in PHP .

Generally speaking, it looks like you want to draw a random number from a Poisson distribution rather than the [uniform distribution]( http://en.wikipedia.org/wiki/Uniform_distribution_(continuous)) . On the wiki page cited above there is a section which specifically states how you can use the continuous distribution to generate a pseudo-Poisson distribution... check it out . Note that you may want to test different values of λ to ensure the distribution works as you want it to.

It depends on what distribution you want to have exactly, ie, what number should appear with what probability.

For instance, for even n you could do the following: generate one integer random number x between 1 and n/2 and generate a second number between 1 and n+1. If y > x you generate x otherwise you generate n-x+1. This should give you the distribution in your example.

I think this should give the requested distribution:

Generate a random number in the range 1 .. x. Generate another one in the range 1 .. x+1. Return the minimum of the two.

Let's think about how your array idea changes the probabilities. Normally every element from 1 to n has a probability of 1/n and is thus equally likely.

Since you have n entries for 1, n-1 entries for 2...1 entry for n, then the total number of entries you have is an arithmetic series. The sum of an arithmetic series counting from 1 to n is n(1+n)/2. So now we know every element's probability should use that as the denominator.

Element 1 has n entries, so it's probability is n/n(1+n)/2. Element 2 is n-1/n(1+n)/2 ... n is 1/n(1+n)/2. That gives a general formula of the numerator as n+1 -i, where i is the number you are checking. That means we now have a function for the probability of any element as n-i+1/n(1+n)/2. all probabilities are between 0 and 1 and sum to 1 by definition, and that is key to the next step.

How can we use this function to skew the number of times an element appears? It's easier with continuous distributions (ie doubles instead of ints) but we can do it. First let's make an array of our probabilities, call it c, and make a running sum of them (cumsum) and store it back in c. If that doesn't make sense, its just a loop like


for(j=0; j < n-1; j++)
   if(j) c[j]+=c[j-1]

Now that we have this cumulative distribution, generate a number i from 0 to 1 (a double, not an int. We can check if i is between 0 and c[0], return 1. if i is between c[1] and c[2] return 2...all the way up to neg


for(j=0; j < n=1;j++)
   if(i %lt;= c[j]) return i+1

This will distribute the integers according to the probabilities you have calculated.

<?php 
//get random number between 1 and 10,000
$random = mt_rand(1, 10000); 
?>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM