研究一下红包算法

有幸被问到了红包算法,当时一时没有想到更好的解决方案,现在花了一点时间研究了一下,下面做详细说明。

先上代码:

$total = 10;        //总金额
$min = 0.01;        //最小红包

$count = 3;         //总红包
$balance = $total;  //剩余红包
$data = [];

for ($i = 1; $i <= $count; $i++) {
    if ($i !== $count) {
        $indexMoney = rand($min * 100, ($balance - ($count - $i) * $min) * 100) / 100;
        $data[] = $indexMoney;
        $balance = $balance - $indexMoney;
    } else {
        $data[] = $balance;
    }
}
$sum = array_sum($data);
var_dump($data);
var_dump($sum);

说明:

1、假设我们有10元钱,准备要发10个红包且10个红包必须全部发完

刚开始发钱时,我们将总金额total赋值给剩余金额balance:因为刚开始剩余金额就是总金额

2、那么第一个人领的钱的范围为0.01到剩余金额减去剩下的人数×最小金额(要保证所有人都有钱)【0.01 到 10 -(10-1)* 0.01】

3、第二个人发钱的范围是【0.01 到 balance  -(10 - 2)* 0.01】

4、那么第N个人为【0.01 到 balance  -(总红包数 - N)* 0.01】

因为这里是按照分来算,所以我们将红包先扩大100倍,也是便于使用rand函数来做,然后我们再除100就保证了当前的金额为分

$indexMoney = rand($min * 100, ($balance - ($count - $i) * $min) * 100) / 100

我们将结果放入一个数组中存下来,同时去更新我们的剩余金额

        $data[] = $indexMoney;
        $balance = $balance - $indexMoney;

当发现红包循环到最后一个时,那么剩余的金额就是最后一个红包的金额,就走的时else部分

当然最后为了验证我们的结果正确与否,我们使用了array_sum来累加

其实这个算法还可以进行补充不够完美,在实际中,我们可能会遇到浮点数的减法丢失精度的问题,所以我们最好加上bcmath扩展来做科学计算,可以使用bcadd和bcsub等来做加减,然后也可以使用php洗牌函数将数组乱序,这样就生成了一个乱序的随机的数组,然后将这个数据返回给上层,保证了每个红包至少都有0.01元且所有红包加起来为我们定义好的总金额。

下面我们看一组结果数据:

  //生成的10个红包
  0 => float 1.98
  1 => float 1.38
  2 => float 2.96
  3 => float 2.3
  4 => float 0.27
  5 => float 0.31
  6 => float 0.67
  7 => float 0.08
  8 => float 0.03
  9 => float 0.02

  //总金额为10元
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值