> 算法為自創,非微信官方算法(僅供參考);如測出有問題,請及時反饋。感謝
原文:[http://flc.ren/2018/04/701.html](http://flc.ren/2018/04/701.html)
### CHANGELOG
* * *
**2018-04-07**
* 修復最后一個紅包輸出未保留2位數
* 修復領取的紅包金額低于最小紅包限制
~~~
<?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));
}
}
// 例子
$coupon = new Coupon(200, 5, 30);
$res = $coupon->handle();
print_r($res);
~~~
運行結果:[http://www.dooccn.com/php7/#i...](http://www.dooccn.com/php7/#id/a512e9be939af0935c8da2ed933a9ee8)
- PHP新特性
- 一些常識
- PHP常見header頭
- Nginx配置文件
- 常用工具類
- PHP實現的一個時間幫助類
- PHP原生生成EXCEL
- PHP地理位置計算
- PHP獲取服務器狀態
- 駝峰轉下劃線
- 百度地圖兩點坐標距離計算
- 判斷是否是url
- 郵件發送類
- 阿拉伯數字轉化為大寫
- 獲取漢字首個拼音
- 根據身份證號獲取星座
- 生成驗證碼類
- 生成唯一ID
- 身份證驗證類
- PHP中文轉拼音
- curl獲取網頁內容
- 快遞查詢api
- 快遞API類
- 上傳圖片類
- 股票類
- 找回密碼類
- 校驗數據規則
- PHP獲取收集相關信息
- 字符串截取助手函數
- 網頁中提取關鍵字
- 檢測瀏覽器語言
- PHP實現微信紅包拆分算法
- 常用函數
- 微信相關
- 網絡知識
- LX1 Laravel / PHP 擴展包視頻教程
- THINKPHP5學習
- 高級查詢
- Vue學習
- Vue全家桶
- Vue-CLI 3.x 自動部署項目至服務器
- Vue2全家桶
- Vue2全家桶之一:vue-cli(vue腳手架)超詳細教程
- Vue2全家桶之二:vue-router(路由)詳細教程,看這個就夠了
- Vue2全家桶之三:vue-resource(不推薦)----axios(推薦)
- 前端相關
- sublime text3 配置less編譯環境
- 服務器搭建相關
- supervisor
- Supervisor 安裝與配置 Linux進程管理
- supervisor 永不掛掉的進程 安裝以及使用
- Supervisor進程管理&開機自啟
- php實現定時任務
- 使用sublime text3 連接sftp/ftp(遠程服務器)
- Redis相關
- linux服務器重啟后導致redis數據丟失
- 搜索引擎SEO
- 百度收錄權威鏈接,指向真正需要收錄的地址rel
- 軟件相關
- sublime
- sublime Text3修改側邊欄的主題
- sublime和vscode比較
- Acrylic DNS Proxy 使用方法
- 技術類網址收藏