PHP几个常用的概率算法
说明:全概率计算为统一设置一个中奖概率;单独概率计算则每个奖品分别可以设置一个中奖概率;
算法一(全概率计算)<br/>
此类中奖概率为所有奖项设置一个总的中奖概率,中奖后再从已有的奖品里面随机抽一个奖品
中奖判断:
1.先按照总体的抽奖概率判断该用户是否中奖<br/>
2.如果中奖的话,则随机从所有奖品里面抽出一个<br/>
3.所有奖品抽完后中奖概率变成0<br/>
如:中奖概率为20%,一等奖1个,二等奖2个,三等奖3个;<br/>
首先判断是否中奖,中奖概率为20%<br/>
中奖的客户再判断中哪个奖项,一等奖的概率:1/(1+2+3);二等奖概率:2/(1+2+3);三等奖概率:3/(1+2+3);<br/>
每次中某个奖品后,相应的奖品数量需要-1,如中出一个三等奖后,相应的中奖概率:一等奖的概率:1/(1+2+2);二等奖概率:2/(1+2+2);三等奖概率:2/(1+2+2);
某个奖品数量抽完后,该奖品中奖概率变成0,如一等奖抽完后,一等奖中奖概率:0/(0+2+3)
全部奖品抽空后,不能再中奖
/** * 抽奖结果,概率计算 * @param $award 奖品数组 * @return array|bool */ private function getAwardresult($award) { if (empty($award)) { return false; } //总的奖项目 $i = count($award); $prob_sum = 0; foreach($award as $item){ $prob_sum += $item['size']; } //总的概率 $award_chance = 20; $rand = mt_rand(1, 10000); //1-10000之间随机取值 $award_chance *= 100; //0.01-100.00的概率 if ($rand <= $award_chance) { $level = mt_rand(1, $i); //中了几等奖 1 一号奖品,2 二号奖品,3 三号奖品,4 四号奖品,5 五号奖品 $num = $award[$i]/$prob_sum; if($num>0){ return $level; } return false; } return false; }
算法二(单独概率计算)<br/>
此类营销活动奖品中奖概率可以单独设置,每次仅需要判断是否中奖不需要二次确认中什么奖品
中奖判断:
根据设置的中奖概率,判断该次抽奖是否中奖,中了什么奖品<br/>
如果某奖品已经是小于等于0,那么这个奖品的获得概率合并到不中奖概率<br/>
所有奖品抽完后,不能继续中奖<br/>
如:一等奖中奖概率为1%,奖品10个,二等奖2%,奖品10个,三等奖3%,奖品20个<br/>
只要一二三等奖奖品没抽空的情况下,不管已经抽出去了多少个一二三等奖,抽中一二三等奖的概率都不变,分别为;1%.2%,3%;
如果一等奖已经抽完了,用户还是抽到1-100中的数字,此时用户并没有中一等奖,因为奖品数量是0,所以还是不中奖
假如数组如下:
$award = array(
array('id' => 1, 'prize_name' => '平板电脑', 'prize_num' => 1, 'prize_prob' => 1),
array('id' => 2, 'prize_name' => '数码相机', 'prize_num' => 5, 'prize_prob' => 2),
array('id' => 3, 'prize_name' => '音箱设备', 'prize_num' => 10, 'prize_prob' => 10),
array('id' => 4, 'prize_name' => '4G优盘', 'prize_num' => 12, 'prize_prob' => 10),
array('id' => 5, 'prize_name' => '10Q币', 'prize_num' => 22, 'prize_prob' => 15),
array('id' => 6, 'prize_name' => '下次没准就能中哦', 'prize_num' => 50, 'prize_prob' => 40),
);
/** * 抽奖结果,概率计算 * @param array $award 奖品数组 * @return array|bool */ private function getAwardresult(array $award) { if (empty($award)) { return false; } //初始化几率区间 $baseNum = 10000; $randNum = mt_rand(1, $baseNum); //总库存,总概率 $prizeTotalNum = array_sum(array_column($award, 'prize_num')); $prizeTotalProb = array_sum(array_column($award, 'prize_prob')); //判断随机数 是否大于 总概率 if (empty($prizeTotalNum) || empty($prizeTotalProb) || $randNum > $prizeTotalProb * 100) { return false; } $vMax = 0; foreach ($award as $key => $v) { $vMin = $vMax; $vMax += $v['prize_prob'] ? ($v['prize_prob'] / 100) * $baseNum : 0; if (empty($v['prize_num']) || $randNum < $vMin || $randNum > $vMax) { return false; } //如果总概率不是100%,就小小的控制一下,这样相当对每一个奖品并发起到了控制 $key = "shake_lock_level_award_{$v['id']}"; if ($prizeTotalProb != 10000 && Redis::getInstance()->get($key)) { return false; } Redis::getInstance()->setex($key, 5, 1); return [ 'id' => $v['id'], 'prize_name' => $v['prize_name'], 'prize_num' => $v['prize_num'], 'prize_prob' => $v['prize_prob'], ]; } return false; }
算法二是一段比较经典的概率算法,$award是一个预先设置的数组,v表示中奖概率大小是0-100,开始是从,10000这个概率范围内筛选一个数是否在他的出现概率范围之内, 如果在,说明中奖,再在总共的奖项中筛选一个数,看中了几等奖,当然还有去判断处理看看该奖项是否还有剩余