<?php /* *Author:Kermit *Time:2015-8-26 *Note:紅包生成隨機算法 */ header("Content-type:text/html;charset=utf-8"); date_default_timezone_set('PRC'); #紅包生成的算法程序 class reward { public $rewardMoney; #紅包金額、單位元 public $rewardNum; #紅包數量 public $scatter; #分散度值1-10000 public $rewardArray; #紅包結果集 #初始化紅包類 public function __construct() { $this->rewardArray=array(); } #執行紅包生成算法 public function splitReward($rewardMoney,$rewardNum,$scatter=100) { #傳入紅包金額和數量 $this->rewardMoney=$rewardMoney; $this->rewardNum=$rewardNum; $this->scatter=$scatter; $this->realscatter=$this->scatter/100; /* *前言:今天我突然這樣一想,比如要把1個紅包分給N個人,實際上就是相當於要得到N個百分比數據 * 條件是這N個百分比之和=100/100。這N個百分比的平均值是1/N。 * 並且這N個百分比數據符合一種正態分布(多數值比較靠近平均值) *觀點:微信紅包里很多0.01的紅包,我覺得這是微信程序里的人為控制,目的是為了防止總紅包數超過總額,先分了幾個0.01的紅包。 * 不然不管是以隨機概率還是正態分布都很難會出現非常多的0.01元紅包。 */ #我的思路:正如上面說的,比如:1個紅包發給5個人,我要得出5個小數,它們的和是1,他們的平均值是1/5 #計算出發出紅包的平均概率值、精確到小數4位。即上面的1/N值。 $avgRand=round(1/$this->rewardNum,4); #紅包的向平均數集中的分布正像數學上的拋物線。拋物線y=ax2,|a|越大則拋物線的開口就越小,|a|越小則拋物線的開口就越大,a>0時開口向上,我們這都是正數,就以a>0來考慮吧。 #程序里的$scatter值即為上方的a,此值除以100,當做100為基准, #通過開方(數學里的拋物線模型,開方可縮小變化值)得出一個小數字較多(小數字多即小紅包多)的隨機分布,據此生成隨機數 $randArr=array(); while(count($randArr)<$rewardNum) { $t=round(sqrt(mt_rand(1,10000)/$this->realscatter)); $randArr[]=$t; } #計算當前生成的隨機數的平均值,保留4位小數 $randAll=round(array_sum($randArr)/count($randArr),4); #為將生成的隨機數的平均值變成我們要的1/N,計算一下生成的每個隨機數都需要除以的值。我們可以在最后一個紅包進行單獨處理,所以此處可約等於處理。 $mixrand=round($randAll/$avgRand,4); #對每一個隨機數進行處理,並剩以總金額數來得出這個紅包的金額。 $rewardArr=array(); foreach($randArr as $key=>$randVal) { $randVal=round($randVal/$mixrand,4); $rewardArr[]=round($this->rewardMoney*$randVal,2); } #對比紅包總數的差異、修正最后一個大紅包 sort($rewardArr); $rewardAll=array_sum($rewardArr); $rewardArr[$this->rewardNum-1]=$this->rewardMoney-($rewardAll-$rewardArr[$this->rewardNum-1]); rsort($rewardArr); #對紅包進行排序一下以方便在前台圖示展示 foreach($rewardArr as $k=>$value) { $t=$k%2; if($t) array_push($this->rewardArray,$value); else array_unshift($this->rewardArray,$value); } $rewardArr=NULL; return $this->rewardArray; } } $money=1000; #總共要發的紅包數; $people=50; #總共要發的人數 $scatter=100; #分散度 $reward=new reward(); $rewardArr=$reward->splitReward($money,$people,$scatter); echo "發放紅包個數:{$people},紅包總金額{$money}元。下方所有紅包總額之和:".array_sum($reward->rewardArray).'元。下方用圖展示紅包的分布'; echo '<hr>'; echo "<table style='font-size:12px;width:600px;border:1px solid #ccc;text-align:left;'><tr><td>紅包金額</td><td>圖示</td></tr>"; foreach($rewardArr as $val) { #線條長度計算 $width=intval($people*$val*300/$money); echo "<tr><td>{$val}</td><td width='500px;text-align:left;'><hr style='width:{$width}px;height:3px;border:none;border-top:3px double red;margin:0 auto 0 0px;'></td></tr>"; } echo "</table>"; ?>