3

I want to choose randomly* between two alternatives with unequal probability.

For instance, when the user presses a button, 25% of the time it would make sound A and 75% of the time, sound B. I can manually do easy ratios like 1:4 and 2:4 but I'm having trouble with ratios like 3:5.

What is the generic way to think about this?

*I mean unpredictable when looked at one-by-one. I notice any question with the word random in it gets a Mensa of pedants.

willc2
  • 38,991
  • 25
  • 88
  • 99

5 Answers5

5

The ration 3:5 is equivalent to 37.5% of the time or 0.375 (3 times it's A, 5 times it's B, so 3/8 is 37.5%). So you can calculate it like this:

random() < 0.375 ? "A" : "B"

From

http://en.wikipedia.org/wiki/Ratio

If there are 2 oranges and 3 apples, the ratio of oranges to apples is shown as 2:3, whereas the fraction of oranges to total fruit is 2/5.

Samuel Neff
  • 73,278
  • 17
  • 138
  • 182
4

For 3:5 you can add them together to get 8, and pick a random integer less than 8. If it's 0, 1, or 2 (three chances) you choose A, and if it's 3, 4, 5, 6, or 7 (five chances) you choose B. Code-wise you'd just check whether your random number is less than 3.

For something like 3:5:4, you'd pick a random number less than 12 (3+5+4) and if it's less than 3 you choose A, otherwise if it's less than 8 (3+5) you choose B, otherwise you choose C.

This can generalize to any number of alternatives, but it's inefficient with lots of alternatives since you have to check the random number against each threshold, which is O(n). This SO question seems to provide some more efficient (but more complex) algorithms for weighted random selection with larger numbers of alternatives.

Community
  • 1
  • 1
Wyzard
  • 33,849
  • 3
  • 67
  • 87
  • 1
    Sam, it's choosing between the alternatives with probabilities 3/8 and 5/8, which sum to 1 and have a 3:5 ratio. Seems right to me. Can you explain what's wrong about it? – Wyzard Dec 02 '10 at 04:52
  • Oh, I see what you mean: I interpreted 3:5 to mean 3 of A for every 5 of B (treating the two values as being proportional to probability density) rather than 3 of A for every 5 trials (treating them as a fraction). The algorithm is correct if you express your probabilities in that way, though. – Wyzard Dec 02 '10 at 04:59
  • you're right, and every other answer here is incorrect. Thanks for following up on my previous incorrect comments. – Samuel Neff Dec 02 '10 at 16:52
  • @Sam, I think all the answers here are true. – Saeed Amiri Dec 02 '10 at 19:06
3

If you have access to a uniform random number distribution between 0 and 1 you can do the following:

Convert the ratio into a fraction, so the ratio will then become some number x. (For example 3:2 will become 3/5 or 0.6) Take a random number y from the uniform [0,1] distribution. If y < x choose the first alternative, otherwise choose the second alternative.

shuttle87
  • 15,466
  • 11
  • 77
  • 106
1

Assuming your random number generator gives back a double value between 0.0 and 1.0, you just do a comparison to the exact ratio you want. In the case of 3 out of 5, you'd check to see if the random value was less than 0.6.

if(rand < 0.6) {
    playSound(A);
}
else {
    playSound(B);
}
Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
1
if (random() % (A+B) < A) 
   do_A() 
else
   do_B();
ruslik
  • 14,714
  • 1
  • 39
  • 40
  • why minus? can you at least explain yourself? – ruslik Dec 02 '10 at 03:56
  • It's for an `int` version of `random()` (and integer values for A and B). For `float` one it would be `if (random() * (A+B) < A)...` – ruslik Dec 02 '10 at 04:39
  • @Sam: When you say `3:5`, it means 3 outcomes of A to 5 outcomes of B on average. What you are expecting have another notation: `prob(A) = 3/5` – ruslik Dec 02 '10 at 14:35