php 随机红包数生成

无论哪种实现方式,随机红包都要遵守几个核心约束(这是和单纯随机数最大的区别):

  1. 总金额固定(比如 100 元分 10 个红包);
  2. 每个红包金额非空(至少 0.01 元,避免分到 0);
  3. 金额随机且符合 "拼手气" 特性(有人多有人少,而非平均);
  4. 所有红包金额之和严格等于总金额。
php 复制代码
/**
 * 随机分配红包金额.
 *
 * @param float|string $totalMoney 总金额(元)
 * @param int          $totalTimes 总次数
 * @param float|string $minMoney   单次最小值(元)
 * @param float|string $maxMoney   单次最大值(元)
 *
 * @return array|false 包含每次红包金额的数组(保留两位小数)|false 参数错误时返回false
 */
function random_red_packet($totalMoney, $totalTimes, $minMoney, $maxMoney)
{
    // 转换为分进行计算,避免浮点数精度问题
    $totalMoneyCent = (int) bcmul($totalMoney, 100);
    $minMoneyCent = (int) bcmul($minMoney, 100);
    $maxMoneyCent = (int) bcmul($maxMoney, 100);

    // 参数合法性校验
    if (
        $totalTimes <= 0
        || $minMoneyCent <= 0
        || $maxMoneyCent < $minMoneyCent
        || $totalMoneyCent < $totalTimes * $minMoneyCent // 总金额不足以分配最小值
        || $totalMoneyCent > $totalTimes * $maxMoneyCent    // 总金额超过最大值总和
    ) {
        return false;
    }

    $redPackets = [];
    $remainingCent = $totalMoneyCent;
    $remainingTimes = $totalTimes;

    for ($i = 0; $i < $totalTimes; ++$i) {
        // 最后一次直接分配剩余金额
        if (1 == $remainingTimes) {
            $currentCent = $remainingCent;
        } else {
            // 计算当前可分配的最大金额:不超过单红包最大值,且剩余次数能满足最小值
            $maxCurrentCent = min(
                $maxMoneyCent,
                $remainingCent - ($remainingTimes - 1) * $minMoneyCent
            );
            // 随机生成当前红包金额(在最小值和最大可分配金额之间)
            $currentCent = mt_rand($minMoneyCent, $maxCurrentCent);
        }

        // 转换为元并保留两位小数
        $redPackets[] = bcdiv($currentCent, 100, 2);

        // 更新剩余金额和次数
        $remainingCent = bcsub($remainingCent, $currentCent, 2);
        --$remainingTimes;
    }

    // 打乱数组(可选,模拟随机顺序)
    shuffle($redPackets);

    return $redPackets;
}
相关推荐
JaguarJack14 小时前
为什么 PHP 闭包要加 static?
后端·php·服务端
ServBay2 天前
垃圾堆里编码?真的不要怪 PHP 不行
后端·php
用户962377954482 天前
CTF 伪协议
php
BingoGo4 天前
当你的 PHP 应用的 API 没有限流时会发生什么?
后端·php
JaguarJack4 天前
当你的 PHP 应用的 API 没有限流时会发生什么?
后端·php·服务端
BingoGo5 天前
OpenSwoole 26.2.0 发布:支持 PHP 8.5、io_uring 后端及协程调试改进
后端·php
JaguarJack5 天前
OpenSwoole 26.2.0 发布:支持 PHP 8.5、io_uring 后端及协程调试改进
后端·php·服务端
JaguarJack6 天前
推荐 PHP 属性(Attributes) 简洁读取 API 扩展包
后端·php·服务端
BingoGo6 天前
推荐 PHP 属性(Attributes) 简洁读取 API 扩展包
php
JaguarJack7 天前
告别 Laravel 缓慢的 Blade!Livewire Blaze 来了,为你的 Laravel 性能提速
后端·php·laravel