1. Background introduction
A while ago, the company's business had a need to generate red envelopes, which are divided into fixed red envelopes and random red envelopes. There is nothing much to say about fixed red envelopes, and random red envelopes require a minimum value. , and the maximum value, there must be at least one maximum value, there can be no minimum value, but any red envelope cannot be less than the minimum value.
I have never done this before and was a little confused, so I went to Baidu and found that all the red envelope algorithms I could find had various bugs. They would either calculate negative values or exceed the maximum value, so Decided to make a set myself.
Still not sure what’s going on? It doesn’t matter, let’s code together!Original text: For example, if you want to distribute 1 red envelope to N people, it is actually equivalent to getting N percentage data The condition is that the sum of these N percentages = 100/100. The average of these N percentages is 1/N. And these N percentage data conform to a normal distribution (most values are closer to the mean).
Interpretation: For example, if I have 1,000 yuan and send out 50 red envelopes, I will first randomly select 50 numbers, and then calculate the average value of these 50 numbers, $avg, using $avg/(1/N ), you get a base $mixrand, and then divide the 50 randomly generated numbers by $mixrand to get the percentage of each number relative to the base $randVal, and then multiply $randVal by 1,000 yuan to get each The specific amount of the red envelope.
##3. Talk is cheap, show me your code!
Red envelope generation core Algorithm:
<?php /* * Author:xx_lufei * Time:2016年9月14日09:55:36 * Note:红包生成随机算法 */ class Reward { public $rewardMoney; #红包金额、单位元 public $rewardNum; #红包数量 #执行红包生成算法 public function splitReward($rewardMoney, $rewardNum, $max, $min) { #传入红包金额和数量,因为小数在计算过程中会出现很大误差,所以我们直接把金额放大100倍,后面的计算全部用整数进行 $min = $min * 100; $max = $max * 100; #预留出一部分钱作为误差补偿,保证每个红包至少有一个最小值 $this->rewardMoney = $rewardMoney * 100 - $rewardNum * $min; $this->rewardNum = $rewardNum; #计算出发出红包的平均概率值、精确到小数4位。 $avgRand = 1 / $this->rewardNum; $randArr = array(); #定义生成的数据总合sum $sum = 0; $t_count = 0; while ($t_count $randVal) { #单个红包所占比例randVal $randVal = round($randVal / $mixrand, 4); #算出单个红包金额 $single = floor($this->rewardMoney * $randVal); #小于最小值直接给最小值 if ($single $max) { $single = $max; } #将红包放入结果数组 $rewardArr[] = $single; } #对比红包总数的差异、将差值放在第一个红包上 $rewardAll = array_sum($rewardArr); $rewardArr[0] = $rewardMoney * 100 - ($rewardAll - $rewardArr[0]);#此处应使用真正的总金额rewardMoney,$rewardArr[0]可能小于0 #第一个红包小于0时,做修正 if ($rewardArr[0] add($rewardArr, $min); } rsort($rewardArr); #随机生成的最大值大于指定最大值 if ($rewardArr[0] > $max) { #差额 $diff = 0; foreach ($rewardArr as $k => &$v) { if ($v > $max) { $diff += $v - $max; $v = $max; } else { break; } } $transfer = round($diff / ($this->rewardNum - $k + 1)); $this->diff($diff, $rewardArr, $max, $min, $transfer, $k); } return $rewardArr; } #处理所有超过最大值的红包 public function diff($diff, &$rewardArr, $max, $min, $transfer, $k) { #将多余的钱均摊给小于最大值的红包 for ($i = $k; $i rewardNum; $i++) { #造随机值 if ($transfer > $min * 20) { $aa = rand($min, $min * 20); if ($i % 2) { $transfer += $aa; } else { $transfer -= $aa; } } if ($rewardArr[$i] + $transfer > $max) continue; if ($diff - $transfer 0) { $i++; $this->diff($diff, $rewardArr, $max, $min, $transfer, $k); } } #第一个红包小于0,从大红包上往下减 public function add(&$rewardArr, $min) { foreach ($rewardArr as &$re) { $dev = floor($re / $min); if ($dev > 2) { $transfer = $min * floor($dev / 2); $re -= $transfer; $rewardArr[$this->rewardNum - 1] += $transfer; } elseif ($dev == 2) { $re -= $min; $rewardArr[$this->rewardNum - 1] += $min; } else { break; } } if ($rewardArr[$this->rewardNum - 1] > $min || $rewardArr[$this->rewardNum - 1] == $min) { return; } else { $this->add($rewardArr, $min); } } }
Details to consider:
The following code is used to control specific business logic, and set aside fixed maximum and minimum red envelope amounts according to specific needs;
When calling splitReward($total, $num,$max - 0.01, $min); in the code, the maximum value I passed in was reduced by 0.01, which ensures that the maximum value of the red envelope generated is absolute. Will not exceed the maximum value we set.<?php class CreateReward{ /* * 生成红包 * author xx 2016年9月23日13:53:38 * @param int $total 红包总金额 * @param int $num 红包总数量 * @param int $max 红包最大值 * */ public function random_red($total, $num, $max, $min) { #总共要发的红包金额,留出一个最大值; $total = $total - $max; $reward = new Reward(); $result_merge = $reward->splitReward($total, $num, $max - 0.01, $min); sort($result_merge); $result_merge[1] = $result_merge[1] + $result_merge[0]; $result_merge[0] = $max * 100; foreach ($result_merge as &$v) { $v = floor($v) / 100; } return $result_merge; } }
4. Pull it out for a walk
Basic code:
Set various initial values
<?php /** * Created by PhpStorm. * User: lufei * Date: 2017/1/4 * Time: 22:49 */ header('content-type:text/html;charset=utf-8'); ini_set('memory_limit', '128M'); require_once('CreateReward.php'); require_once('Reward.php'); $total = 50000; $num = 300000; $max = 50; $min = 0.01; $create_reward = new CreateReward();
Performance test:
Because of the memory_limit limit, I only measured the average of 5 times, and the results were all around 1.6s.
for($i=0; $irandom_red($total, $num, $max, $min); $time_end = microtime_float(); $time[] = $time_end - $time_start; } echo array_sum($time)/5; function microtime_float() { list($usec, $sec) = explode(" ", microtime()); return ((float)$usec + (float)$sec); }
Running results:
Detect whether there are negative values, whether there is a maximum value, how many maximum values there are, and whether there is a value smaller than the minimum value;
##Data check:
$reward_arr = $create_reward->random_red($total, $num, $max, $min);
sort($reward_arr);//正序,最小的在前面
$sum = 0;
$min_count = 0;
$max_count = 0;
foreach($reward_arr as $i => $val) {
if ($i第".($i+1)."个红包,金额为:".$val."<br>";
}
if ($val == $max) {
$max_count++;
}
if ($val 已生成红包总金额为:'.($sum/100).';总个数为:'.count($reward_arr).'<hr>';
//检测有没有小于0的值
echo "<br>最大值:".($val/100).',共有'.$max_count.'个最大值,共有'.$min_count.'个值比最小值小';
Run results:
##Normal distribution chart:
Note that when publishing the chart, do not give too many red envelopes, otherwise the page will render If it doesn’t come out, it will collapse
##
$reward_arr = $create_reward->random_red($total, $num, $max, $min); $show = array(); rsort($reward_arr); //为了更直观的显示正态分布效果,需要将数组重新排序 foreach($reward_arr as $k=>$value) { $t=$k%2; if(!$t) $show[]=$value;; else array_unshift($show,$value); } echo "设定最大值为:".$max.',最小值为:'.$min.'<hr>'; echo "
红包金额 | 图示 |
{$val} |
Run result:
Four functions of php: stats_standard_deviation (standard deviation), stats_variance (variance), stats_kurtosis (kurtosis), stats_skew (skewness)PS: A friend asked me if the data I generated has been verified mathematically to see if it conforms to the standard normal distribution, because my mathematics No, I really haven’t thought about this. I just looked like him and assumed he was.
Since I have encountered this problem, I must solve it, so I used php
to calculate it. The calculated result is relatively close to the normal distribution when the amount of data is small. But when the amount of data increases, it cannot be viewed. I don’t quite understand this. If you are interested, you can find out the reason.
built-in function
Using the above functions requires
installation stats extension@Download Address
5. In the end
At this point, I have finished writing the red envelope. I don’t know if I can get a 50 yuan salary increase, but it should be able to solve the urgent need.
##Oh yes, I also left this code to package and download
The above is the detailed content of PHP algorithm for generating random red envelopes. For more information, please follow other related articles on the PHP Chinese website!

APHPDependencyInjectionContainerisatoolthatmanagesclassdependencies,enhancingcodemodularity,testability,andmaintainability.Itactsasacentralhubforcreatingandinjectingdependencies,thusreducingtightcouplingandeasingunittesting.

Select DependencyInjection (DI) for large applications, ServiceLocator is suitable for small projects or prototypes. 1) DI improves the testability and modularity of the code through constructor injection. 2) ServiceLocator obtains services through center registration, which is convenient but may lead to an increase in code coupling.

PHPapplicationscanbeoptimizedforspeedandefficiencyby:1)enablingopcacheinphp.ini,2)usingpreparedstatementswithPDOfordatabasequeries,3)replacingloopswitharray_filterandarray_mapfordataprocessing,4)configuringNginxasareverseproxy,5)implementingcachingwi

PHPemailvalidationinvolvesthreesteps:1)Formatvalidationusingregularexpressionstochecktheemailformat;2)DNSvalidationtoensurethedomainhasavalidMXrecord;3)SMTPvalidation,themostthoroughmethod,whichchecksifthemailboxexistsbyconnectingtotheSMTPserver.Impl

TomakePHPapplicationsfaster,followthesesteps:1)UseOpcodeCachinglikeOPcachetostoreprecompiledscriptbytecode.2)MinimizeDatabaseQueriesbyusingquerycachingandefficientindexing.3)LeveragePHP7 Featuresforbettercodeefficiency.4)ImplementCachingStrategiessuc

ToimprovePHPapplicationspeed,followthesesteps:1)EnableopcodecachingwithAPCutoreducescriptexecutiontime.2)ImplementdatabasequerycachingusingPDOtominimizedatabasehits.3)UseHTTP/2tomultiplexrequestsandreduceconnectionoverhead.4)Limitsessionusagebyclosin

Dependency injection (DI) significantly improves the testability of PHP code by explicitly transitive dependencies. 1) DI decoupling classes and specific implementations make testing and maintenance more flexible. 2) Among the three types, the constructor injects explicit expression dependencies to keep the state consistent. 3) Use DI containers to manage complex dependencies to improve code quality and development efficiency.

DatabasequeryoptimizationinPHPinvolvesseveralstrategiestoenhanceperformance.1)Selectonlynecessarycolumnstoreducedatatransfer.2)Useindexingtospeedupdataretrieval.3)Implementquerycachingtostoreresultsoffrequentqueries.4)Utilizepreparedstatementsforeffi


Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

SublimeText3 Linux new version
SublimeText3 Linux latest version

Safe Exam Browser
Safe Exam Browser is a secure browser environment for taking online exams securely. This software turns any computer into a secure workstation. It controls access to any utility and prevents students from using unauthorized resources.

VSCode Windows 64-bit Download
A free and powerful IDE editor launched by Microsoft

PhpStorm Mac version
The latest (2018.2.1) professional PHP integrated development tool

MantisBT
Mantis is an easy-to-deploy web-based defect tracking tool designed to aid in product defect tracking. It requires PHP, MySQL and a web server. Check out our demo and hosting services.
