首頁 > 後端開發 > php教程 > PHP用拋物線的模型實作微信紅包生成演算法的程式原始碼

PHP用拋物線的模型實作微信紅包生成演算法的程式原始碼

不言
發布: 2023-03-24 14:08:01
原創
1996 人瀏覽過


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

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

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

<?php

/*
 *Author:Kermit
 *Time:2015-8-26
 *Note:红包生成随机算法
 */ 

header("Content-type:text/html;charset=utf-8");
date_default_timezone_set(&#39;PRC&#39;);

#红包生成的算法程序
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).&#39;元。下方用图展示红包的分布&#39;;
echo &#39;<hr>&#39;;
echo "<table style=&#39;font-size:12px;width:600px;border:1px solid #ccc;text-align:left;&#39;><tr><td>红包金额</td><td>图示</td></tr>";
foreach($rewardArr as $val)
{
	#线条长度计算
	$width=intval($people*$val*300/$money);
	echo "<tr><td>{$val}</td><td width=&#39;500px;text-align:left;&#39;><hr style=&#39;width:{$width}px;height:3px;border:none;border-top:3px double red;margin:0 auto 0 0px;&#39;></td></tr>";	
}
echo "</table>";
?>
登入後複製




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

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

#相關推薦:

php微信公眾號開發之現金紅包



以上是PHP用拋物線的模型實作微信紅包生成演算法的程式原始碼的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板