verjas - 1 year ago 46

PHP Question

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 Source

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.)