上次项目中有个抽奖活动,中奖概率算法整理成一篇笔记
/**
* 中奖概率算法
* v表示中奖概率,注意其中的v必须为整数,可以将对应的奖项的v设置成0,即意味着该奖项抽中的几率是0,数组中v的总和(基数),基数越大越能体现概率的准确性。本例中v的总和为100,那么 特等奖 对应的中奖概率就是1%,如果v的总和是10000,那中奖概率就是万分之一。
*
* $arr = array(
array('id'=>1,'name'=>'特等奖','v'=>1),
array('id'=>2,'name'=>'一等奖','v'=>5),
array('id'=>3,'name'=>'二等奖','v'=>10),
array('id'=>4,'name'=>'三等奖','v'=>12),
array('id'=>5,'name'=>'四等奖','v'=>22),
array('id'=>6,'name'=>'没中奖','v'=>50)
);
*
*/
if (!function_exists("lottery_arithmetic")){
function lottery_arithmetic($status) {
$proArr = [];
switch ($status){
case 1: //普通中奖
$proArr = array(
array('id'=>1,'name'=>'一等奖','v'=>1), //百分之十
array('id'=>2,'name'=>'二等奖','v'=>3),
array('id'=>3,'name'=>'二等奖','v'=>3),
array('id'=>4,'name'=>'二等奖','v'=>4),
array('id'=>5,'name'=>'二等奖','v'=>4),
array('id'=>6,'name'=>'三等奖','v'=>30),
array('id'=>7,'name'=>'三等奖','v'=>20),
array('id'=>8,'name'=>'三等奖','v'=>20),
array('id'=>9,'name'=>'三等奖','v'=>20),
);
break;
case 2: //一定中奖
$proArr = array(
array('id'=>1,'name'=>'一等奖','v'=>1), //百分之十
array('id'=>2,'name'=>'二等奖','v'=>3),
array('id'=>3,'name'=>'二等奖','v'=>3),
array('id'=>4,'name'=>'二等奖','v'=>4),
array('id'=>5,'name'=>'二等奖','v'=>4),
array('id'=>6,'name'=>'三等奖','v'=>30),
array('id'=>7,'name'=>'三等奖','v'=>20),
array('id'=>8,'name'=>'三等奖','v'=>20),
array('id'=>9,'name'=>'三等奖','v'=>20),
);
break;
default:
}
$result = array();
$arr = [];
foreach ($proArr as $key => $val) {
$arr[$key] = $val['v'];
}
// 概率数组的总概率「为100」
$proSum = array_sum($arr);
asort($arr);// 根据键值对数组进行升序排序
// 概率数组循环
foreach ($arr as $k => $v) {
$randNum = mt_rand(1, $proSum); // 在 1和 总权重 之间返回随机整数
if ($randNum <= $v) {
$result = $proArr[$k];
break;
} else {
$proSum -= $v;
}
}
return $result;
}
}
使用示例
dd(lottery_arithmetic(1));