PHP微信红包生成算法的程序源码(用抛物线的模型实现)

代码如下:

 1 <?php
 2 /*
 3  * 红包生成随机算法
 4  */
 5 header("Content-type:text/html;charset=utf-8");
 6 date_default_timezone_set('PRC');
 7 
 8 #红包生成的算法程序
 9 class reward
10 {
11     public $rewardMoney;       #红包金额、单位元
12     public $rewardNum;               #红包数量
13     public $scatter;           #分散度值1-10000
14     public $rewardArray;       #红包结果集
15 
16     #初始化红包类
17     public function __construct()
18     {
19         $this->rewardArray = array();
20     }
21 
22     #执行红包生成算法
23     public function splitReward($rewardMoney, $rewardNum, $scatter = 100)
24     {
25         #传入红包金额和数量
26         $this->rewardMoney = $rewardMoney;
27         $this->rewardNum = $rewardNum;
28         $this->scatter = $scatter;
29         $this->realscatter = $this->scatter / 100;
30         /*
31          *前言:今天我突然这样一想,比如要把1个红包分给N个人,实际上就是相当于要得到N个百分比数据
32          *     条件是这N个百分比之和=100/100。这N个百分比的平均值是1/N。
33          *     并且这N个百分比数据符合一种正态分布(多数值比较靠近平均值)
34          *观点:微信红包里很多0.01的红包,我觉得这是微信程序里的人为控制,目的是为了防止总红包数超过总额,先分了几个0.01的红包。
35          *     不然不管是以随机概率还是正态分布都很难会出现非常多的0.01元红包。
36          */
37         #我的思路:正如上面说的,比如:1个红包发给5个人,我要得出5个小数,它们的和是1,他们的平均值是1/5
38         #计算出发出红包的平均概率值、精确到小数4位。即上面的1/N值。
39         $avgRand = round(1 / $this->rewardNum, 4);
40         #红包的向平均数集中的分布正像数学上的抛物线。抛物线y=ax2,|a|越大则抛物线的开口就越小,|a|越小则抛物线的开口就越大,a>0时开口向上,我们这都是正数,就以a>0来考虑吧。
41         #程序里的$scatter值即为上方的a,此值除以100,当做100为基准,
42         #通过开方(数学里的抛物线模型,开方可缩小变化值)得出一个小数字较多(小数字多即小红包多)的随机分布,据此生成随机数
43         $randArr = array();
44         while (count($randArr) < $rewardNum) {
45             $t = round(sqrt(mt_rand(1, 10000) / $this->realscatter));
46             $randArr[] = $t;
47         }
48         #计算当前生成的随机数的平均值,保留4位小数
49         $randAll = round(array_sum($randArr) / count($randArr), 4);
50         #为将生成的随机数的平均值变成我们要的1/N,计算一下生成的每个随机数都需要除以的值。我们可以在最后一个红包进行单独处理,所以此处可约等于处理。
51         $mixrand = round($randAll / $avgRand, 4);
52         #对每一个随机数进行处理,并剩以总金额数来得出这个红包的金额。
53         $rewardArr = array();
54         foreach ($randArr as $key => $randVal) {
55             $randVal = round($randVal / $mixrand, 4);
56             $rewardArr[] = round($this->rewardMoney * $randVal, 2);
57         }
58         #对比红包总数的差异、修正最后一个大红包
59         sort($rewardArr);
60         $rewardAll = array_sum($rewardArr);
61         $rewardArr[$this->rewardNum - 1] = $this->rewardMoney - ($rewardAll - $rewardArr[$this->rewardNum - 1]);
62         rsort($rewardArr);
63         #对红包进行排序一下以方便在前台图示展示
64         foreach ($rewardArr as $k => $value) {
65             $t = $k % 2;
66             if ($t) array_push($this->rewardArray, $value);
67             else array_unshift($this->rewardArray, $value);
68         }
69         $rewardArr = NULL;
70         return $this->rewardArray;
71     }
72 }
73 
74 $money = 1000;    #总共要发的红包数;
75 $people = 50;     #总共要发的人数
76 $scatter = 100;    #分散度
77 $reward = new reward();
78 $rewardArr = $reward->splitReward($money, $people, $scatter);
79 echo "发放红包个数:{$people},红包总金额{$money}元。下方所有红包总额之和:" . array_sum($reward->rewardArray) . '元。下方用图展示红包的分布';
80 echo '<hr>';
81 echo "<table style='font-size:12px;600px;border:1px solid #ccc;text-align:left;'><tr><td>红包金额</td><td>图示</td></tr>";
82 foreach ($rewardArr as $val) {
83     #线条长度计算
84     $width = intval($people * $val * 300 / $money);
85     echo "<tr><td>{$val}</td><td width='500px;text-align:left;'><hr style='{$width}px;height:3px;border:none;border-top:3px double red;margin:0 auto 0 0px;'></td></tr>";
86 }
87 echo "</table>";
88 ?>

在上传的文件里需要改一下:

$t=round(sqrt(mt_rand(1,10000)/$this->realscatter));,要控制值不为能0,我改成了1,没有测试,可能需要改大点,因为开方后的数值会缩小。

也可以对这行的值直接进行ceil处理, 就不会出现红包为0的数了。

对于scatter的值我没有多做研究,不过根据抛物线的数学模型,这个值的意义可以使抛物线的张口放大缩小,即可以让红包的值分散或者集中。

链接:https://www.php.cn/php-weizijiaocheng-393575.html

原文地址:https://www.cnblogs.com/clubs/p/11950560.html