PHP algorithm for generating random red envelopes
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 < $rewardNum) { #随机产出四个区间的额度 $c = rand(1, 100); if ($c < 15) { $t = round(sqrt(mt_rand(1, 1500))); } else if ($c < 65) { $t = round(sqrt(mt_rand(1500, 6500))); } else if ($c < 95) { $t = round(sqrt(mt_rand(6500, 9500))); } else { $t = round(sqrt(mt_rand(9500, 10000))); } ++$t_count; $sum += $t; $randArr[] = $t; } #计算当前生成的随机数的平均值,保留4位小数 $randAll = round($sum / $rewardNum, 4); #为将生成的随机数的平均值变成我们要的1/N,计算一下每个随机数要除以的总基数mixrand。此处可以约等处理,产生的误差后边会找齐 #总基数 = 均值/平均概率 $mixrand = round($randAll / $avgRand, 4); #对每一个随机数进行处理,并乘以总金额数来得出这个红包的金额。 $rewardArr = array(); foreach ($randArr as $key => $randVal) { #单个红包所占比例randVal $randVal = round($randVal / $mixrand, 4); #算出单个红包金额 $single = floor($this->rewardMoney * $randVal); #小于最小值直接给最小值 if ($single < $min) { $single += $min; } #大于最大值直接给最大值 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] < 0) { rsort($rewardArr); $this->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 < $this->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) { $rewardArr[$i] += $diff; $diff = 0; break; } $rewardArr[$i] += $transfer; $diff -= $transfer; } if ($diff > 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; $i<5; $i++) { $time_start = microtime_float(); $reward_arr = $create_reward->random_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<3) {
echo "<br />第".($i+1)."个红包,金额为:".$val."<br />";
}
if ($val == $max) {
$max_count++;
}
if ($val < $min) {
$min_count++;
}
$val = $val*100;
$sum += $val;
}
//检测钱是否全部发完
echo '<hr>已生成红包总金额为:'.($sum/100).';总个数为:'.count($reward_arr).'<hr>';
//检测有没有小于0的值
echo "<br />最大值:".($val/100).',共有'.$max_count.'个最大值,共有'.$min_count.'个值比最小值小';
Copy after login
Run results:
$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<3) { echo "<br />第".($i+1)."个红包,金额为:".$val."<br />"; } if ($val == $max) { $max_count++; } if ($val < $min) { $min_count++; } $val = $val*100; $sum += $val; } //检测钱是否全部发完 echo '<hr>已生成红包总金额为:'.($sum/100).';总个数为:'.count($reward_arr).'<hr>'; //检测有没有小于0的值 echo "<br />最大值:".($val/100).',共有'.$max_count.'个最大值,共有'.$min_count.'个值比最小值小';
##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 "<table style='font-size:12px;width:600px;border:1px solid #ccc;text-align:left;'><tr><td>红包金额</td><td>图示</td></tr>"; foreach($show as $val) { #线条长度计算 $width=intval($num*$val*300/$total); 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>";
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!

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

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics

PHP 8.4 brings several new features, security improvements, and performance improvements with healthy amounts of feature deprecations and removals. This guide explains how to install PHP 8.4 or upgrade to PHP 8.4 on Ubuntu, Debian, or their derivati

If you are an experienced PHP developer, you might have the feeling that you’ve been there and done that already.You have developed a significant number of applications, debugged millions of lines of code, and tweaked a bunch of scripts to achieve op

Visual Studio Code, also known as VS Code, is a free source code editor — or integrated development environment (IDE) — available for all major operating systems. With a large collection of extensions for many programming languages, VS Code can be c

JWT is an open standard based on JSON, used to securely transmit information between parties, mainly for identity authentication and information exchange. 1. JWT consists of three parts: Header, Payload and Signature. 2. The working principle of JWT includes three steps: generating JWT, verifying JWT and parsing Payload. 3. When using JWT for authentication in PHP, JWT can be generated and verified, and user role and permission information can be included in advanced usage. 4. Common errors include signature verification failure, token expiration, and payload oversized. Debugging skills include using debugging tools and logging. 5. Performance optimization and best practices include using appropriate signature algorithms, setting validity periods reasonably,

A string is a sequence of characters, including letters, numbers, and symbols. This tutorial will learn how to calculate the number of vowels in a given string in PHP using different methods. The vowels in English are a, e, i, o, u, and they can be uppercase or lowercase. What is a vowel? Vowels are alphabetic characters that represent a specific pronunciation. There are five vowels in English, including uppercase and lowercase: a, e, i, o, u Example 1 Input: String = "Tutorialspoint" Output: 6 explain The vowels in the string "Tutorialspoint" are u, o, i, a, o, i. There are 6 yuan in total

This tutorial demonstrates how to efficiently process XML documents using PHP. XML (eXtensible Markup Language) is a versatile text-based markup language designed for both human readability and machine parsing. It's commonly used for data storage an

Static binding (static::) implements late static binding (LSB) in PHP, allowing calling classes to be referenced in static contexts rather than defining classes. 1) The parsing process is performed at runtime, 2) Look up the call class in the inheritance relationship, 3) It may bring performance overhead.

What are the magic methods of PHP? PHP's magic methods include: 1.\_\_construct, used to initialize objects; 2.\_\_destruct, used to clean up resources; 3.\_\_call, handle non-existent method calls; 4.\_\_get, implement dynamic attribute access; 5.\_\_set, implement dynamic attribute settings. These methods are automatically called in certain situations, improving code flexibility and efficiency.
