PHP用拋物線的模型實現微信紅包產生演算法的程式源碼

來源:互聯網
上載者:User

今天研究了一下紅包的產生演算法,看似覺得簡單,實際弄起來不是那麼回事,當然如果只是覺得用個rand產生幾個隨機數的話,那也就沒有什麼意義了。

發紅包應該有點講究啊,得讓分配的所有人都能拿到非0的紅包,同時要讓大多數人拿到平均值左右的紅包。

其它也不多說了,我在程式裡已經寫了很多的注釋,上代碼如下:

<?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>";?>




在上傳的檔案裡需要改一下54行:$t=round(sqrt(mt_rand(1,10000)/$this->realscatter));,要控制值不為能0,我改成了1,沒有測試,可能需要改大點,因為開方後的數值會縮小。也可以對這行的值直接進行ceil處理, 就不會出現紅包為0的數了。

對於scatter的值我沒有多做研究,不過根據拋物線的數學模型,這個值的意義可以使拋物線的張口放大縮小,即可以讓紅包的值分散或者集中

相關推薦:

php公眾號開發之現金紅包

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.