<?php

/**
* 红包分配算法
*
* example
* $coupon = new Coupon(200, 5);
* $res = $coupon->handle();
* print_r($res);
* @author Flc <2018-04-06 20:09:53>
* @see http://flc.ren | http://flc.io | https://github.com/flc1125
*/
class Coupon
{
/**
* 红包金额
* @var float
*/
protected $amount; /**
* 红包个数
* @var int
*/
protected $num; /**
* 领取的红包最小金额
* @var float
*/
protected $coupon_min; /**
* 红包分配结果
* @var array
*/
protected $items = []; /**
* 初始化
* @param float $amount 红包金额(单位:元)最多保留2位小数
* @param int $num 红包个数
* @param float $coupon_min 每个至少领取的红包金额
*/
public function __construct($amount, $num = 1, $coupon_min = 0.01)
{
$this->amount = $amount;
$this->num = $num;
$this->coupon_min = $coupon_min;
} /**
* 处理返回
* @return array
*/
public function handle()
{
// A. 验证
if ($this->amount < $validAmount = $this->coupon_min * $this->num) {
throw new Exception('红包总金额必须≥'.$validAmount.'元');
} // B. 分配红包
$this->apportion(); return [
'items' => $this->items,
];
} /**
* 分配红包
*/
protected function apportion()
{
$num = $this->num; // 剩余可分配的红包个数
$amount = $this->amount; //剩余可领取的红包金额 while ($num >= 1) {
// 剩余一个的时候,直接取剩余红包
if ($num == 1) {
$coupon_amount = $this->decimal_number($amount);
} else {
$avg_amount = $this->decimal_number($amount / $num); // 剩余的红包的平均金额 $coupon_amount = $this->decimal_number(
$this->calcCouponAmount($avg_amount, $amount, $num)
);
}
$this->items[] = $coupon_amount; // 追加分配 $amount -= $coupon_amount;
--$num;
} shuffle($this->items); //随机打乱
} /**
* 计算分配的红包金额
*
* @param float $avg_amount 每次计算的平均金额
* @param float $amount 剩余可领取金额
* @param int $num 剩余可领取的红包个数
* @return float
*/
protected function calcCouponAmount($avg_amount, $amount, $num)
{
// 如果平均金额小于等于最低金额,则直接返回最低金额
if ($avg_amount <= $this->coupon_min) {
return $this->coupon_min;
} // 浮动计算
$coupon_amount = $this->decimal_number($avg_amount * (1 + $this->apportionRandRatio())); // 如果低于最低金额或超过可领取的最大金额,则重新获取
if ($coupon_amount < $this->coupon_min
|| $coupon_amount > $this->calcCouponAmountMax($amount, $num)
) {
return $this->calcCouponAmount($avg_amount, $amount, $num);
} return $coupon_amount;
} /**
* 计算分配的红包金额-可领取的最大金额
* @param float $amount
* @param int $num
*/
protected function calcCouponAmountMax($amount, $num)
{
return $this->coupon_min + $amount - $num * $this->coupon_min;
} /**
* 红包金额浮动比例
*/
protected function apportionRandRatio()
{
// 60%机率获取剩余平均值的大幅度红包(可能正数、可能负数)
if (rand(1, 100) <= 60) {
return rand(-70, 70) / 100; // 上下幅度70%
} return rand(-30, 30) / 100; // 其他情况,上下浮动30%;
} /**
* 格式化金额,保留2位
* @param float $amount
* @return float
*/
protected function decimal_number($amount)
{
return sprintf('%01.2f', round($amount, 2));
} } // 例子
$price_total = 0;
$total = $surplus_total = 30;
$max_num = $surplus_num = 8;
echo "总共{$total}元,随机生成{$max_num}个红包".'</br>'; for($i=0;$i<$max_num;$i++){
$coupon = new Coupon($surplus_total, $surplus_num, 0.01);
$res = $coupon->handle();
$money = $res['items'][0];
$price_total += $money;
$surplus_total = bcsub($surplus_total, $money, 2);  //解决高精度问题
echo '第'.($i+1).'个随机红包:'.$money.'还剩下'.($surplus_total).'元'.'<br>';
$surplus_num--;
}

示例演示:

php 随机红包算法的更多相关文章

  1. PHP实现微信随机红包算法和微信红包的架构设计简介

    微信红包的架构设计简介: 原文:https://www.zybuluo.com/yulin718/note/93148 @来源于QCon某高可用架构群整理,整理朱玉华. 背景:有某个朋友在朋友圈咨询微 ...

  2. PHP随机红包算法

    2017年1月14日 14:19:14 星期六 一, 整体设计 算法有很多种, 可以自行选择, 主要的"架构" 是这样的, 用redis decr()命令去限流, 用mysql去记 ...

  3. php 固定红包 + 随机红包算法

    <?php /** * 随机红包+固定红包算法[策略模式] * copyright (c) 2016 http://blog.csdn.net/CleverCode */ //配置传输数据DTO ...

  4. C# 随机红包算法

    static void Main(string[] args) { ; ; double minAmount = 0.01; Random r = new Random(); ; i < num ...

  5. 微信红包随机生成算法(PHP版)

    /** * 求一个数的平方 * @param $n */ function sqr($n){ return $n*$n; } /** * 生产min和max之间的随机数,但是概率不是平均的,从min到 ...

  6. 微信红包算法TEST

    1.基本算法 设定总金额为10元,有N个人随机领取:N=1 则红包金额=X元: N=2 为保证第二个红包可以正常发出,第一个红包金额=0.01至9.99之间的某个随机数 第二个红包=10-第一个红包金 ...

  7. PHP实现微信红包算法和微信红包的架构设计简介

    微信红包的架构设计简介: 原文:https://www.zybuluo.com/yulin718/note/93148 @来源于QCon某高可用架构群整理,整理朱玉华. 背景:有某个朋友在朋友圈咨询微 ...

  8. php红包算法函数[优化]

    php红包算法 <?php header("Content-Type: text/html;charset=utf-8");//输出不乱码,你懂的 $total=10000; ...

  9. php微信红包算法

    微信红包算法.php /**生成红包的函数*/ function getRandMoney($totalMoney, $totalPeople=2, $miniMoney=1){ $randRemai ...

随机推荐

  1. 逆向工程-真码保存在系统文件破解QQ游戏对对碰助手

    1)注册栏中输入任意值测试 1.2)记录弹出的关键字对话框 2.1)发送至PEID进行查壳 2.2)发现无壳 2.3)将软件载入OllyDBG程序 2.4)在反汇编栏下右键选择中文搜索引擎->智 ...

  2. :before和::before的区别

    单冒号(:)用于CSS3伪类,双冒号(::)用于CSS3伪元素.伪元素和伪类之所以这么容易混淆,是因为他们的效果类似而且写法相仿,但实际上 css3 为了区分两者,已经明确规定了伪类用一个冒号来表示, ...

  3. 关于javascript中的变量对象和活动对象

    https://segmentfault.com/a/1190000010339180 https://zhuanlan.zhihu.com/p/26011572 https://www.cnblog ...

  4. python基础5 while循环

    一.while循环: while  条件: 代码块 例: n=0 while n<10: print(n) n=n+1   #n自加1 ,满足n<10,继续循环 输出结果: 1 2 3 4 ...

  5. ionic3 添加多个自定义组件

    往往我们创建自定义组件一般都不止只会创建一个自定义组件,创建多个方式如下. 1.创建自定义组件 ionic g component select-car-no ionic g component ae ...

  6. jeecg自定义datagrid查询

    为什么要写这篇文章? 我们了解,使用 jeecg 提供的 CriteriaQuery 查询方式,确实能满足绝大数的需求,但是往往有那么个比较复杂的情况,需要我们直接去写 sql,比如多表查询呀等等等等 ...

  7. php json 中文不转义 & 转义为中文

    JSON_UNESCAPED_UNICODE private function decodeUnicode($str){ return preg_replace_callback('/\\\\u([0 ...

  8. [PCL]模型拟合方法——随机采样一致性

    SACSegmentation封装了多种Ransac方法,包括: RandomSampleConsensus, LeastMedianSquares, MEstimatorSampleConsensu ...

  9. Golang 之协程详解

    转自:https://www.cnblogs.com/liang1101/p/7285955.html 一.Golang 线程和协程的区别 备注:需要区分进程.线程(内核级线程).协程(用户级线程)三 ...

  10. 关于JS的原型与继承笔记

    1.什么是原型? 原型就是公用的方法或者属性. 1.prototype本质上还是一个JavaScript对象: 2.每个函数都有一个默认的属性prototype,而这个prototype的constr ...