Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

algorithm

php

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!

like image 764
verjas Avatar asked May 15 '15 07:05

verjas


2 Answers

That's because the true chances of getting each in your code are :

$10 - 0.1*0.9 = 9%

$50 - 0.1*0.1*0.9 = 0.9%

$500 - 0.1*0.1*0.1 = 0.1%


This is not because of mt_rand(). This is just a statistics problem. Try running more iterations, and you'll see the numbers converge to the numbers above.

As you can see with the calculations above, you don't get $10 by getting it right the first time, you get $10 by getting it right the first time (10%), AND getting it wrong the second time (90%).

Following that logic, you can extend the same math for $50 (getting it right the first two times, 10% and 10%, THEN getting it wrong on the third time, 90%), and for $500 (you get the drill).

With your specific code, the computations for the true probability is as above.


See code in the accepted answer for the correct code with accurate probabilities.

like image 172
Zaenille Avatar answered Nov 14 '22 21:11

Zaenille


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

like image 29
M Oehm Avatar answered Nov 14 '22 21:11

M Oehm