On Sat, 11 Oct 2003 23:04:33 GMT, "Alexander Ross" <al******@bleen.net> wrote:
is there any way to get a weighted random number other than something like
this:
array = (1,2,2,3,3,3,4,4,4,5,5,6)
and then get a random val from teh array?
Yes, but that's probably the simplest. You can produce that array from an
array of weights if you wanted.
<pre>
<?php
function weighted_rand($weights) {
foreach ($weights as $value => $weight)
for ($i=0; $i<$weight; $i++)
$values[] = $value;
return $values[mt_rand(0, count($values)-1)];
}
$num_runs = 40000;
$weights = array(1=>1, 2=>2, 3=>3);
for ($i=0; $i < $num_runs; $i++) {
$rand = weighted_rand($weights);
if (isset($results[$rand]))
$results[$rand]++;
else
$results[$rand] = 1;
}
ksort($results);
$total_weight = 0;
foreach ($weights as $weight)
$total_weight += $weight;
foreach ($results as $value => $freq) {
printf("%d : expected %8d (%3.2f%%), actual %8d (%3.2f%%)\n",
$value,
$num_runs * ($weights[$value] / $total_weight),
($weights[$value] / $total_weight) * 100.0,
$freq, $freq/$num_runs * 100.0);
}
?>
</pre>
Outputs:
1 : expected 6666 ( 16.67%), actual 6624 ( 16.56%)
2 : expected 13333 ( 33.33%), actual 13383 ( 33.46%)
3 : expected 20000 ( 50.00%), actual 19993 ( 49.98%)
Or you could skip creating the array with repeated values and work directly
off the weight array:
function weighted_rand($weights) {
$total_weight = 0;
foreach ($weights as $weight)
$total_weight += $weight;
$rand = mt_rand(1, $total_weight);
$total_weight = 0;
foreach ($weights as $value => $weight) {
$total_weight += $weight;
if ($rand <= $total_weight)
return $value;
}
}
Output to make sure it's still weighting correctly:
1 : expected 6666 ( 16.67%), actual 6554 ( 16.38%)
2 : expected 13333 ( 33.33%), actual 13352 ( 33.38%)
3 : expected 20000 ( 50.00%), actual 20094 ( 50.23%)
--
Andy Hassall (an**@andyh.co.uk) icq(5747695) (
http://www.andyh.co.uk)
Space: disk usage analysis tool (
http://www.andyhsoftware.co.uk/space)