Maison  >  Article  >  développement back-end  >  PHP utilise un modèle parabolique pour implémenter le code source du programme de l'algorithme de génération d'enveloppe rouge WeChat

PHP utilise un modèle parabolique pour implémenter le code source du programme de l'algorithme de génération d'enveloppe rouge WeChat

不言
不言original
2018-04-20 12:36:431935parcourir


Aujourd'hui, j'ai étudié l'algorithme de génération d'enveloppes rouges. Cela semble simple, mais en pratique, ce n'est pas si différent. Bien sûr, si vous voulez simplement utiliser un rand pour générer quelques aléatoires. des chiffres, alors ça n’a pas de sens.

Donner des enveloppes rouges devrait être un peu particulier, afin que toutes les personnes assignées puissent recevoir une enveloppe rouge non nulle, et en même temps, la plupart des gens devraient obtenir une enveloppe rouge moyenne.

Pas grand chose d'autre à dire. J'ai écrit beaucoup de commentaires dans le programme. Le code est le suivant :

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


.



Vous devez modifier la ligne 54 dans le fichier téléchargé : $t=round(sqrt(mt_rand(1,10000 ) /$this->realscatter));, pour contrôler la valeur de 0, je l'ai changée en 1. Je ne l'ai pas encore testée. Vous devrez peut-être la modifier plus grande, car la valeur après la racine carrée le fera. rétrécir. Vous pouvez également effectuer directement un traitement plafond sur la valeur de cette ligne, afin que le nombre d'enveloppes rouges de valeur 0 n'apparaisse pas.

Je n'ai pas fait beaucoup de recherches sur la valeur de scatter, mais selon le modèle mathématique de la parabole, la signification de cette valeur peut faire dilater ou rétrécir l'embouchure de la parabole, c'est-à-dire qu'elle peut rendre la valeur de l'enveloppe rouge dispersée ou concentrée

Recommandations associées:

PHP WeChat développement de compte public cash enveloppe rouge



Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn