Reputation: 53
How to generate 6 random integers which add up to 8, and each one is less than or equal to 2?
eg. 1,2,1,2,2,0
For far I have found the method which give the random integers with fixed sum but how to impose the constraints on these integers.
Upvotes: 5
Views: 3424
Reputation: 51998
I would recommend a hit-and-miss approach to guarantee a uniform distribution of generated sequences satisfying the constraint. It is easy to work out that the probability of 6 random integers in {0,1,2} adding up to 8 is roughly 12.3%, so not too many trials are needed before a hit. Here is a Python implementation:
import random
def randNums(n,a,b,s):
#finds n random ints in [a,b] with sum of s
hit = False
while not hit:
total, count = 0,0
nums = []
while total < s and count < n:
r = random.randint(a,b)
total += r
count += 1
nums.append(r)
if total == s and count == n: hit = True
return nums
Here is the output from 5 runs:
>>> for i in range(5): print(randNums(6,0,2,8))
[2, 1, 0, 2, 1, 2]
[0, 2, 2, 1, 1, 2]
[2, 2, 0, 2, 0, 2]
[2, 2, 0, 1, 1, 2]
[1, 2, 1, 1, 1, 2]
On Edit: I was curious about the exact probabilities so wrote a program to exhaustively enumerate all possibilities. Random sequences of length 6 in {0,1,2} can be thought of as random integers in 0 to 3^6-1 = 728 written in base 3. Just calculate the digit sums for base-3 numbers in that range and see which = 8:
def toBase3(n):
digits = []
q,r = divmod(n,3)
while q > 0:
digits.append(r)
q,r = divmod(q,3)
digits.append(r)
return ''.join(str(i) for i in reversed(digits))
def dsum(s):
return sum(int(d) for d in s)
hits = []
for n in range(729):
s = toBase3(n)
if dsum(s) == 8: hits.append(s)
hits = [('0'*(6-len(s)))+s for s in hits] #left-pad with '0' if needed
s = ''.join(hits)
print("%d valid sequences for prob. of %f" % (len(hits),len(hits)/3.0**6))
print("%d zeros in those sequences for a prob. of %f" % (s.count('0'),s.count('0')/540.0))
print("%d ones in those sequences for a prob. of %f" % (s.count('1'),s.count('1')/540.0))
print("%d twos in those sequences for a prob. of %f" % (s.count('2'),s.count('2')/540.0))
Output:
90 valid sequences for prob. of 0.123457
90 zeros in those sequences for a prob. of 0.166667
180 ones in those sequences for a prob. of 0.333333
270 twos in those sequences for a prob. of 0.500000
As an odd curiosity, the probability that such a random sequence of length 6 sums to 8, with more decimal places displayed, is
90/729 = 0.123456790 (repeating)
I didn't realize that there was such a nice probability interpretation of the pleasing decimal 0.1234567
. It's a pity that 8
isn't after the 7
.
Upvotes: 2
Reputation: 3579
First, not all of it can be truly random, since those requirements make a few things necessary.
For example, there MUST be at least two 2's in order for 6 total numbers from the set {0,1,2} to make it to 8. So two of our end integers are preordained. May as well not waste energy figuring them out because of that. So that starts us off at 2,2,?,?,?,?.
Now that leaves us with a challenge consisting of getting 4 numbers from the set {0,1,2} that equal 4. The possible combinations for that are (not counting the 0's) two 2's, one 2 and two 1's, and four 1's. Literally only 3 possible combos. So it makes sense to just set them into an array and pick one at random...and those arrays can start with the two 2's we already know will be needed. So:
var possibles = [
[2,2,2,2,0,0],
[2,2,2,1,1,0],
[2,2,1,1,1,1]
];
var randomInd = Math.floor( Math.random()*possibles.length ); // random number from 0-2
var myArr = possibles[randomInd]; // picks a random entry from possibles
Now that we've got a random Array consisting of the possible ways it could go down, we just have to shuffle it up. We can use a standard shuffling function for that:
function shuffle(arr)
{
var curInd = arr.length, tempVal, randInd;
while (0 !== curInd) {
randInd = Math.floor(Math.random()*curInd);
curInd -= 1;
tempVal = arr[curInd];
arr[curInd] = arr[randInd];
arr[randInd] = tempVal;
}
}
shuffle(myArr);
alert(myArr); // will give "random" sequence
You could also "weight" certain combinations by better representing them in the possibles
array (i.e. make 2 entries of a certain combo instead of 1).
Note - I don't see any specific language required, so for anyone curious that's javascript. A JSFiddle can be seen of it working here: https://jsfiddle.net/6xaeLp4g/
Upvotes: 2
Reputation: 262504
How about this:
This will not result in uniformly distributed integers on [0,2] (but you did not say what distribution you need), the numbers will skew towards equal heights across the array.
Upvotes: 3