<?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. 网络编程之socketserver以及socket更多方法

    关于socketserver 关于socket的更多方法 服务端套接字函数: s.bind() 绑定(主机,端口号)到套接字 s.listen() 开始tcp监听 s.accept () 被动接受tc ...

  2. Dapp开发教程一 Asch Dapp Hello World

    1 基本流程 Asch有三种net,localnet,testnet,mainnet,后两种是发布到线上的,可通过公网访问. 第一种localnet是运行在本地的.只有一个节点的私链,主要是为了方便本 ...

  3. request之额外路径

    谈到额外路径 ,首先要明白映射路径,映射路径是servlet处理的路径,在web.xml中配置.比如配置一个/emp的映射路径,意味着客户端可以通过http:+项目路径+/emp访问服务器的项目,而所 ...

  4. 数据结构day1:排序

    1,冒泡排序算法的python实现 def bubble_sort(alist): pass count = len(alist)-1 for index in range(count,0,-1): ...

  5. 【C++】基于邻接矩阵的图的深度优先遍历(DFS)和广度优先遍历(BFS)

    写在前面:本博客为本人原创,严禁任何形式的转载!本博客只允许放在博客园(.cnblogs.com),如果您在其他网站看到这篇博文,请通过下面这个唯一的合法链接转到原文! 本博客全网唯一合法URL:ht ...

  6. Head First Python-Python简单处理文件

    前面介绍了自定义格式化输出列表函数printList(),下面再介绍下格式化列表项及列表项的排序. 这里有一组列表数据,记录运动员跑步时间的,要求按照时间大小进行排序.这里每项数据记录的时间格式不一样 ...

  7. mysql_主从同步

    在这里我就不说怎么搭建 Mysql 数据库了!如果有需要可以参照我前面的博文. 此博文主要说配置 Linux  数据库   主从   下面我们开始进入正题. master:192.168.31.200 ...

  8. Machine Learning, Homework 9, Neural Nets

    Machine Learning, Homework 9, Neural NetsApril 15, 2019ContentsBoston Housing with a Single Layer an ...

  9. win7系统64位配置Oracle 的ODBC数据源

    1.安装oracle客户端 2.在如下路径启动odbc数据源 3.选择系统DSN-添加,选择oracle驱动 4.填写信息如下,填写数据源名称等信息后输入用户名和密码测试连接

  10. Scala中 zip或者zipWithIndex的用法

    问题:你要遍历一个有序集合,同时你又想访问一个循环计数器,但最重要的是你真的不需要手动创建这个计数器.解决方案:    使用zipWithIndex或者zip方法来自动地创建一个计数器,假设你有一个有 ...