开发者

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

开发者 https://www.devze.com 2023-01-08 01:36 出处:网络
This is mo开发者_运维技巧re of a maths/general programming question, but I am programming with PHP is that makes a difference.

This is mo开发者_运维技巧re 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?


Generate a random number between 0 and a random number!


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


Generate number n which is 0 <= n < 1, multiply it by itself, than multiply by x, run floor on it and add 1. Sorry I used php toooo long ago to write code in it


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.


Quick and simple:

rand(1, rand(1, n))


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, i.e., 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 n. e.g.

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); 
?>
0

精彩评论

暂无评论...
验证码 换一张
取 消