根据很多需求的使用场景,如发红包、砍价类需求,这两个功能都有一个同样的特点,如下:
ログイン後にコピー
红包
1.合計金額
2.赤い封筒の数
3 .赤い封筒の最小数
交渉
1. 交渉総額
2. 交渉を完了するために必要な人数 (人数)需要により異なります)
- 固定番号交渉番号
- ランダム交渉番号数
- 指定ランダム交渉人数
ポイント2:その3つルールはすべてルールに従って人数を決める必要がある
3. 最低交渉金額
開発アイデア
検証パラメータ
最小金額を 0 未満にすることはできません
合計金額を数量に最小金額を掛けた値より大きくすることはできません
#分配金額
平均金額(合計金額/残数量)を取得
分配金額平均金額以下
最大金額に達した場合に最小金額を直接配分
金額を取得振幅比
最小値は-1
より小さいことはできません 最大値は1
を超えることはできません 分布量振幅計算を取得(平均 * (1振幅比
))
分配量判定分配量
が最小量
または分配量#未満である ##は
より大きい 請求できる最大金額((最低残高総額) - (残高 × 最低金額)) を再分配します
最後の 1 つが残っている場合は、残りのすべての金額が再分配されます
開発コード
<?php /** * 发送红包 * Class sandRed */ class sandRed { #红包金额 protected $amount; #红包个数 protected $num; #领取的红包最小金额 protected $minAmount; #红包分配结果 protected $amountArr = []; public function __construct($amount, $num = 1, $minAmount = 1) { $this->amount = $amount; $this->num = $num; $this->minAmount = $minAmount; } /** * 处理返回 * @return array * @throws Exception */ public function handle() { # 验证 if ($this->amount < $validAmount = $this->minAmount * $this->num) { throw new Exception('红包总金额必须≥'.$validAmount.'元'); } # 分配红包 $this->allot(); return $this->amountArr; } /** * 分配红包 */ protected function allot() { # 剩余可分配的红包个数 $num = $this->num; # 剩余可领取的红包金额 $amount = $this->amount; while ($num >= 1) { if ($num == 1) { # 剩余一个的时候,直接取剩余红包 $coupon_amount = $this->formattingAmount($amount); } else { # 平均金额 $avgAmount = $this->formattingAmount($amount / $num); # 分配金额 $countAllotAmount = $this->countAllotAmount($avgAmount, $amount, $num); # 剩余的红包的平均金额 $coupon_amount = $this->formattingAmount($countAllotAmount); } # 追加分配金额 $this->amountArr[] = $coupon_amount; # 计算剩余金额 $amount -= $coupon_amount; $num--; } # 随机打乱 // shuffle($this->amountArr); } /** * 计算分配的红包金额 * @param float $avgAmount 每次计算的平均金额 * @param float $amount 剩余可领取金额 * @param int $num 剩余可领取的红包个数 * @return float */ protected function countAllotAmount($avgAmount, $amount, $num) { # 如果平均金额小于等于最低金额,则直接返回最低金额 if ($avgAmount <= $this->minAmount) { return $this->minAmount; } # 浮动比率 $floatingRate = $this->floatingRate(); # 分配金额 $allotAmount = $avgAmount * (1 + $floatingRate); # 浮动计算 $coupon_amount = $this->formattingAmount($allotAmount); # 如果低于最低金额或超过可领取的最大金额,则重新获取 if ($coupon_amount < $this->minAmount || $coupon_amount > $this->canReceiveMaxAmount($amount, $num)) { return $this->countAllotAmount($avgAmount, $amount, $num); } return $coupon_amount; } /** * 计算分配的红包金额-可领取的最大金额 * @param $amount * @param $num * @return float|int */ protected function canReceiveMaxAmount($amount, $num) { return $this->minAmount + $amount - $num * $this->minAmount; } /** * 红包金额浮动比例 * @return float|int */ protected function floatingRate() { # 60%机率获取剩余平均值的大幅度红包(可能正数、可能负数) if (rand(1, 100) <= 60) { # 上下幅度70% return rand(-70, 70) / 100; } # 其他情况,上下浮动30%; return rand(-30, 30) / 100; } /** * 格式化金额,保留2位 * @param $amount * @return string */ protected function formattingAmount($amount) { return sprintf('%01.2f', round($amount, 2)); } }
ログイン後にコピー
- 総額
$amount = 1;
ログイン後にコピー
- 割り当て数量
$num = 10;
ログイン後にコピー
- 最小値
$minAmount = 0.01; $red = new sandRed($amount, $num, $minAmount); $res = $red->handle(); print_r($res);
ログイン後にコピー
- 出力結果 [0.10,0.04,0.08,0.04,0.16,0.14,0.11,0.13,0.11,0.09]
echo array_sum($res);
ログイン後にコピー
- 出力結果 1