verjas verjas - 4 months ago 11
PHP Question

Lottery algorithm - PHP - math seems good, but is the function valid?

I want to make a custom lottery extraction to motivate users to participate in an online experiment. The rules are:


  • 10% to get 10$

  • 1% chance to get 50$

  • 0.1% chance to get 500$



The lottery is a PHP function that gets called once and returns the prize (0, 10, 50 or 500). I created the function below, and after 70 000 trials the statistics are:


  • 9.11% for 10$

  • .91% for 50$

  • .01% for 500$



Should I be worried about the algorithm? Is there a better way to create a good distribution of chances than mt_rand ?

function lottery() {
// winnings before extraction
$win=0;

// choose a winning number between 1 and 10
$target=mt_rand(1,10);

// make three independent extractions, each with 1/10 probability
if (mt_rand(1,10) == $target) {
// if first extraction is the winning number -> prize=10
// probability: 1/10
$win=10;

if (mt_rand(1,10) == $target) {
// if second extraction is ALSO the winning number -> prize=50
// probability: 1/10 * 1/10
$win=50;

if (mt_rand(1,10) == $target) {
// if third extraction is ALSO the winning number -> prize=500
// probability: 1/10 * 1/10 * 1/10
$win=500;
}
}
}
// return the prize
return $win;
}


Thank you for helping a newbie!

Answer

You have four outcomes with given probabilities:

  • 0.1% probability to win $500.
  • 1% probability to win $500.
  • 10% probability to win $500.

The fourth outcome - no win - is 100% minus the sum of the other three outcomes, namely 88.9%.

Mark Gabriel has explained why your initial code was off: By promoting 10% of the people who have won $10 to $50 winners, you take them away from the pool of $10 winner, which will be only 9% of all people.

Pham Trung has contributed a solution that takes the winners of higher amounts from the pool of non-winners so far and adjusts the probabilities. That's a workable solution, but the easiest solution is in my opintion to call the random number generator just once.

This solution also reflects the ticket analogy best: You place 10,000 tickets in a box. The 1,000 tickets from 1 to 1000 win $10. The 100 tickets from 1001 to 1100 win $50. The ten tickets from 1101 to 1110 win $500. All 8890 tickets from 1111 on don't win anything:

function lottery() {
    var pick = Math.floor(10000 * Math.random());
               // random number in the range [0, 10000).

    if (pick < 1000) return 10;
    if (pick < 1100) return 50;
    if (pick < 1110) return 500;

    return 0;
}

In this code, the tickets have only their number written on them. You pick one. Then you check whether the ticket number is eligible for $10. If not, you check the same ticket whether it may bet a $50 win. There is really just one random action involved.

(I've used a zero-based random-number function in Javascript instead of PHP's mt_rand, but I think the solution is clear.)