php分割金额_PHP实现微信红包金额拆分及原理解析

微信红包有个好玩的地方,比如可以将 10 元放入红包,设置红包数量为 10 个.然后系统会自动将这 10 元拆分,有的人可能领到了几块钱,而有的人就只领到了几分钱.

实现方法:function getRedPacket($price, $total = 10)

{

$min_price = 0.01;

$temp = [];

$return = [];

for ($i = 1; $i 

// 红包金额的最大值

$max_total = ($price - ($total - $i) * $min_price) / ($total - $i);

if ($max_total 

// 随机产生一个红包金额

$money = @mt_rand($min_price * 100, $max_total * 100) / 100;

// 剩余红包总额

$price = $price - $money;

// 保留两位有效数字

$temp[$i] = round($money, 2);

}

$temp[$i] = round($price, 2);

$return['money'] = $temp;

$return['total'] = array_sum($temp);

return $return;

}

调用该方法,可以得到这样的数据(实际返回的是数组 json 格式需要自己转):{

"money": {

"1": 1.06,

"2": 0.01,

"3": 0.45,

"4": 1.28,

"5": 0.91,

"6": 0.7,

"7": 1.79,

"8": 1.87,

"9": 1,

"10": 0.93

},

"total": 10

}

其实实现方法不难,重点是代码中的这句:$max_total = ($price - ($total - $i) * $min_price) / ($total - $i);

十个十元的红包,循环九次执行这个算法之后,得到的结果是:(10 - (10 - 1) *0.01) / (10 - 1)    得出结果    1.1011111111111

(9.45 - (10 - 2) *0.01) / (10 - 2)  得出结果    1.17125

(9.3 - (10 - 3) *0.01) / (10 - 3)   得出结果    1.3185714285714

(9.06 - (10 - 4) *0.01) / (10 - 4)  得出结果    1.5

(7.72 - (10 - 5) *0.01) / (10 - 5)  得出结果    1.534

(6.91 - (10 - 6) *0.01) / (10 - 6)  得出结果    1.7175

(6.62 - (10 - 7) *0.01) / (10 - 7)  得出结果    2.1966666666667

(6.29 - (10 - 8) *0.01) / (10 - 8)  得出结果    3.135

(5.45 - (10 - 9) *0.01) / (10 - 9)  得出结果    5.44

可以看出,该算法就是: ( 剩余的金额 - ( 总金额 - 次数 ) * 0.01 ) / ( 总金额 - 次数 )

第一次循环时,剩余的金额是 10 因为总金额就 10 ,然后经过计算得出的结果是 1.1011111111111 如果传的是 10 元 分成 10 个,那么第一次的结果总是一致的.

拿到了第一个结果,就可以根据最低金额(0.01 一分钱),和刚才计算出来的金额,进行生成随机数.

比如生成一个随机数是 0.53 ,就将这个数存入数组,因为这个数就是第一个红包的金额了,存的时候注意下保留两位小数.

说一下,这里将最低金额 0.01 和 最大金额(算法算出的金额) 进行乘 100 计算, 算完再除 100 ,原因是为了对 "分" 做到更加精确,比如写 微信/支付宝/银联 的支付开发,支付金额都是用单位为分的金额传输的.

得到了第一个红包的金额,就可以将总金额 减 刚才得到的随机数(第一个红包),就得到了目前的剩余总金额,然后一直还需要循环八次,重复执行得到九个红包的金额.

可能有人会问,还有最后一个红包金额呢? 其实很简单,你都得到了九个红包了,并且每次执行代码都会得到一个 "目前的红包总额", 那第十个红包不就是这个总额了...

所以,根据上面的代码可以拆分红包,但是... 基本上最后一个红包是最大的,比如拆分三次的结果:{

"money": {

"1": 0.73,

"2": 0.6,

"3": 0.89,

"4": 0.47,

"5": 0.65,

"6": 0.2,

"7": 0.37,

"8": 0.94,

"9": 1.76,

"10": 3.39

},

"total": 10

}{

"money": {

"1": 0.53,

"2": 1.09,

"3": 0.61,

"4": 0.42,

"5": 0.8,

"6": 0.99,

"7": 0.06,

"8": 2.44,

"9": 0.84,

"10": 2.22

},

"total": 10

}{

"money": {

"1": 0.22,

"2": 0.16,

"3": 0.86,

"4": 1.28,

"5": 0.58,

"6": 1.52,

"7": 1.13,

"8": 1.62,

"9": 0.76,

"10": 1.87

},

"total": 10

}

博主并没有特意把第十个红包最大的数据拿出来说,而是三次执行代码,拿到的数据就是这样的.

都是第十个(最后一个)红包的金额最大,如果介意,可以使用这个函数把数组值打乱:shuffle(array &array);

比如这样调用:$data = getRedPacket(10, 10);

// 以下数据没有打乱 基本上第十个红包是最大的

echo json_encode($data);

// 进行打乱数据

shuffle($data['money']);

// 再次输出的数据 和第一次输出的数据顺序就不一样了

echo json_encode($data);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值