生成随机数方法有很多种,我觉得比较好的一种思路就是先计算剩余金额的平均值, 然后根据剩余金额的平局值获取最大值或者最小值距离平均值之间的一个正太分布值(范围内的随机值,保证在最大值和最小值之间 。

<?php

class RedPacket
{
    /**
     * @param float $rmb 红包总金额
     * @param int $num 红包合适
     * @param int $kind int 0 随机 1平均
     * @param int $max  最大红包金额
     * @return array|bool
     */
    public static function create($rmb, $num, $kind = 0, $max = 0)
    {
        if ($num < 2) $kind = 1;
        $min = 0.01;//最小金额
        $packets = [];
        switch ($kind) {
            case 1://固定金额红包
                $money = sprintf("%.2f", $rmb / $num);
                for ($i = 1; $i <= $num; $i++) {
                    $packets[] = $money;
                }
                return $packets;
            default://随机红包
                if ($min * $num > $rmb) {
                    return false;
                }
                if ($num * $max < $rmb || $max + $num * $min > $rmb) {//验证最大红包金额是否正确
                    $max = $rmb / 3;
                }

                while ($num >= 1) {
                    $num--;
                    $kMin = max($min, $rmb - $num * $max);
                    $kMax = min($max, $rmb - $num * $min);
                    $kAvg = $rmb / ($num + 1);
                    //获取最大值和最小值的距离之间的最小值
                    $kDis = min($kAvg - $kMin, $kMax - $kAvg);
                    //获取0到1之间的随机数与距离最小值相乘得出浮动区间,这使得浮动区间不会超出范围
                    $r = ((float)(rand(1, 10000) / 10000) - 0.5) * $kDis * 2;
                    $k = sprintf("%.2f", $kAvg + $r);
                    $rmb -= $k;
                    $packets[] = $k;
                }

                shuffle($packets);
                return $packets;
        }
    }
}

下面是生成10元10个红包最大5元的数据:


下面是生成100元20个红包最大30元的数据:

可以看出来效果还是很好的。

发表回复

您的电子邮箱地址不会被公开。