tags:

views:

904

answers:

15

I want to run a function that has 2 different outcomes, but I want each outcome to be truly 50%. I am assuming rand(0,1) is the way to go, but I am curious if that could possibly favor one over the other. What is the best way to get a 50/50 outcome?

Thanks.

EDIT: thanks guys I don't want it to be random though, I want the outcome to be 101010101 not 111001101. Maybe I should just update a data-base with the last value output and then return the opposite?

EDIT2: OK I am sorry my last edit was misleading. I am only calling the function once per user and assigning that value as a cookie to the user. I want each visiting user to receive a 1 or a 0 in the order 1010101.

+1  A: 

According to the php manual rand(0,1) is the way to go. But it all depends on how good the random number generator is.

RobS
A: 

nothing is truly 50/50. If you want 50/50 then make the function so that the first 5 outcomes are 1 and the other 5 are 2 etc etc.

rand is meant for random number generation. That means than it can give 10 times the same result in a row, but hey thats random.

PoweRoy
+13  A: 

in PHP mt_rand() is a better random number generator

mt_rand(0,1);

Is enough and should generate a pretty good 50/50 value.

Quote about mt_rand:

Many random number generators of older libcs have dubious or unknown characteristics and are slow. By default, PHP uses the libc random number generator with the rand() function. The mt_rand() function is a drop-in replacement for this.

It uses a random number generator with known characteristics using the » Mersenne Twister, which will produce random numbers four times faster than what the average libc rand() provides.

Bill had a good link regarding a visual example. I do not know what PHP the user had there for PHP but since he included the code i have hosted it on my server (Linux with PHP 5.1.6)

Ólafur Waage
+6  A: 

Response to edited question: If you want to maintain an exact 50% ratio, then randomness is the last thing you want. For your purposes you probably just want to assign each new user (no cookie detected) an autonumber from your database, then give the even numbered user's one page and the odd numbered user's the other page (as RobS suggested in a comment).

if( ($user_id % 2) == 0 )
    // user id is even
else
    // user id is odd

Original answer: PHP's rand() function isn't a particularly good pseudo-random number generator (see a Simple Visual Example). I'd recommend mt_rand() instead.

Bill the Lizard
A: 

maybe you can try mt_rand(0,1) instead of rand(0,1)

andi
+1  A: 

Both (rand() and mt_rand()) return a good 50%/50% chance.

Here is an example:

$array1 = array(0,0);
$array2 = array(0,0);

for ($x = 0; $x < 10000; $x++) {
  $array1[mt_rand(0,1)] ++;
  $array2[rand(0,1)] ++;
}

print_r($array1);
print_r($array2);

Results:

Array 1 (mt_rand):
  [0] => 4910
  [1] => 5090
Array 2 (rand):
  [0] => 4970
  [1] => 5030

As per author's request, he wants a fair distribution. So try something like this:

$digits = 200;
$array = array_fill(0, $digits/2, 0); 
for ($x = 0; $x < $digits/2; $x++)
  $array[] = 1;
shuffle($array);

Equal distribution and sufficiently random. (Suggested by Brian)

St. John Johnson
A: 

Pseudo-randomness can never be true randomness. Every computation of random numbers based on a seed or by other means has some level of pre-determinance that may or may not emerge in an obvious way - such as mini-patterns. The best you can hope for is almost 50/50.

karim79
+1  A: 

Disclaimer: This is a stupid thing to do for your particular problem, but if you insist on distrusting your random number generator to be evenly distributed...

The classic algorithm for generating a a 50/50 result when you don't trust that your generator to be evenly distributed is the following algorithm. Be aware that this algorithm is more intended for fixing random numbers than pseudo random numbers and may in fact make mod-based results worse:

  1. Generate two random bits A and B.
  2. If A==B, goto 1
  3. Return B

YOu can also guarantee equal distribution by just starting with lots of 1s and 0s (evenly distributed) and randomly shuffling them.

Brian
A: 

while it is a pseudo random generator it will never reach 50/50 ... read sth. about random number generators here: http://www.robertnz.net/true_rng.html

Tobiask
A: 

if you just want alternating 1 and 0's:

$n = 0;
$myval = ($n==1 ? $n=0 : $n=1);
garyLynch
+1  A: 

Depending on the specific context in which you will use this number (e.g. a per-user basis, lifetime of application, etc.) you can store it in a number of locations, $_SESSION, a database value, or if the scope only covers the current page then you can save it on directly in that page's code.

An easy way to toggle the value is:

$val = 1 - $val;

For a database call:

UPDATE YourTable SET `next_value` = 1 - `next_value`

etc...

John Rasch
See, I think this solution is pretty slick...but much less obvious in what it actually does...I think someone reading it would wonder why the heck this code was written. And if $val (or next_value) were to somehow get messed up, everything from then on would be wrong.
Beska
Yeah, it would definitely be better wrapped in a function ToggleNextValue() or something, but it's really up to the developer to make sure he's not changing values he has no business changing.
John Rasch
A: 

If you seriously want it to return the opposite value on each iteration...

function flip() {
    static $truthiness = false;
    $truthiness = !$truthiness;
    return $truthiness;
}

which should return true, false, true, false, true, etc...

Of course, this only works if the PHP interpreter stays in memory between calls.

Also, if you don't know what the static keyword does, see the PHP manual entry on variable scope.

R. Bemrose
Right, but the function is only run once per user, when someone else on a different system visits I want them to get the oppisite, when I said 10101 I meant for each visitor.
John Isaacks
I would have to check, but if you are using mod_php or something like APC, I *think* it keeps static variables around between users. I don't have any way to test where I'm at now (we use Java/C# here).
R. Bemrose
A: 

This 10101010 is not random, it is a pattern.
result = not result

dbasnett
A: 

This is in response to your comment to your original post:

Your goal is to see which version of the page generates more sales.

It makes more sense to randomly show each page to a visitor than to flip ABABAB for each successive visitor.

While I can't imagine any reason for systematic bias with your method, you can't rule it out. (far fetched scenario: some tracking bot "follows" users to your page, and so user 1 gets A, bot gets B, user 2 gets A, bot get B, etc.)

Achieving better randomness is more sensible when doing a study like you're doing than making sure each page gets displayed exactly 50% of the time.

Baltimark
+1  A: 

RobS has a good solution in the comments, basically saying that each user can get a sequential number, then by using that number % 2, you either get a 0 or a 1, which will determine which page to serve up. Of course, even that isn't absolutely guaranteed to give exactly a 50/50 ratio...it could be an odd number of people!

Also depending on how you determine users, it may be worth verifying that there's not some kind of correlation that would lend even numbered people to be more likely to purchase...unlikely, but just something to keep in mind.

There is an alternate solution for you, where you wouldn't have to worry about odd unexpected correlations: based on your comments and modified question, you're just trying to get a fair analysis comparison between how effective two different page layouts are, you could simply divide each page layout sales by the number of times it was randomly served up. ie, you use your random number generator, and keep track of how many times it gives 0 to serve up page A, and how many times it gives 1 to serve up page B.

Say you made $50,000 in sales on page A with 43 hits, and $46,000 in sales on page B with 38 hits, you simply do the math...

Page A                      Page B

50000                       46000
----- = 1163 $/hit          ----- = 1211 $/hit
  43                          38

Giving page B the slight advantage.

Beska