微信拼手气红包探秘

        大约2周前,孩子学校组织“学校数学智慧节——做数学研究”活动,我们选了一个主题:怎样才能抢到更大的红包。

        为了让孩子有更好的参与感,我们特意设计了比较简单的测试CASE。首先,我和老大负责发红包,大家都可以抢。一共4组测试,每组10个红包,红包分别是2人抢、3人抢、5人抢、10人抢。完事后,我和孩子们一起记录数据,分析规律,忙得不亦乐乎,居然发现一个有趣的现象...

先上数据:

图1:2人红包测试

图2:3人红包测试

图3:5人红包测试

图4:10人红包测试

        每组测试都显示,倒数第2个抢到红包的人抢到红包的总金额用于是明显高于其他人的。

        那么下一个问题来了,怎么才能成为倒数第二个抢到🧧的人呢? 大家有没有好办法~~

        并且,大家通过测试是否还有其它的洞察呢?

        为了让这个研究增加些深度,我特意查阅了微信🧧相关的资料,供参考:

        随机分配红包金额时一般需要遵循3个规则:(1)所有人抢到金额之和等于红包总金额,不能超过,也不能少于;(2)抢到的红包金额至少是一分钱;(3)要保证抢到红包的人获取到的红包金额是随机的。

        实际上,微信群红包采用的是二倍均值法,也就是每次随机上限为剩余红包金额均值的两倍。

        为什么微信群红包要搞一个最大上限,因为如果不设置一个最大上限,会出现一种不公平的现象。就是越在前边领取红包的同学,其可随机范围越大,获得大额红包的几率也越高。一旦前边的同学随机到一个较大的金额,后边的同学可以随机的范围就逐步收窄,抢红包就变成了一个拼手速的游戏了。

       只是二倍均值法理解起来更随机一些,或者咋一看感觉比较随机,其实最终导致第一个可能抢到的最大红包明显受限,且最后2个人抢到的红包总额较大。

      另外,按理说按照二倍均值法的原理,最后2个红包的范围应该差不多。但实际上倒数第二人抢到的红包金额比倒数第一人要多不少,感觉财付通的架构师还有特殊处理没说出来,他是怎么处理和考虑的呢?

欢迎关注微信公众号:数据苦行僧icon-default.png?t=LBL2https://mp.weixin.qq.com/s?__biz=Mzg4OTczMTE4Nw==&mid=2247483664&idx=1&sn=969a64b012132b7fe3766e26ce66d863&chksm=cfe6200cf891a91a88f1cf9e97f05039b0766c773469dd6c4de07d3b5edeeeaa429ef9b2c9e1&token=1345348838&lang=zh_CN#rd

以下是Java实现微信手气红包算法的代码: ```java import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; import java.util.Random; public class RedPacketUtil { /** * 拆分红包 * * @param totalAmount 红包总金额(单位:元) * @param totalPeople 红包总人数 * @return 拆分后的红包金额列表 */ public static List<BigDecimal> splitRedPacket(BigDecimal totalAmount, int totalPeople) { List<BigDecimal> amountList = new ArrayList<>(); Random random = new Random(); BigDecimal leftAmount = totalAmount; int leftPeople = totalPeople; for (int i = 0; i < totalPeople - 1; i++) { // 随机生成一个红包金额,范围为:0.01元 ~ 剩余平均值的两倍 BigDecimal amount = BigDecimal.valueOf(random.nextDouble()) .multiply(leftAmount.divide(BigDecimal.valueOf(leftPeople), 2, BigDecimal.ROUND_HALF_UP)) .multiply(BigDecimal.valueOf(2)) .setScale(2, BigDecimal.ROUND_HALF_UP); amountList.add(amount); leftAmount = leftAmount.subtract(amount); leftPeople--; } amountList.add(leftAmount); return amountList; } /** * 计算红包总金额 * * @param amountList 红包金额列表 * @return 红包总金额(单位:元) */ public static BigDecimal getTotalAmount(List<BigDecimal> amountList) { BigDecimal totalAmount = BigDecimal.ZERO; for (BigDecimal amount : amountList) { totalAmount = totalAmount.add(amount); } return totalAmount; } public static void main(String[] args) { BigDecimal totalAmount = BigDecimal.valueOf(10); // 红包总金额为10元 int totalPeople = 5; // 拆分红包的总人数为5人 List<BigDecimal> amountList = splitRedPacket(totalAmount, totalPeople); System.out.println(amountList); } } ``` 使用示例: ```java BigDecimal totalAmount = BigDecimal.valueOf(10); // 红包总金额为10元 int totalPeople = 5; // 拆分红包的总人数为5人 List<BigDecimal> amountList = RedPacketUtil.splitRedPacket(totalAmount, totalPeople); // 拆分红包 BigDecimal total = RedPacketUtil.getTotalAmount(amountList); // 计算红包总金额 ``` 实现思路: 1. 先定义一个红包总金额和拆分红包的总人数; 2. 初始化一个空的红包金额列表和一个Random对象; 3. 循环拆分红包,每次生成一个随机金额,范围为:0.01元 ~ 剩余平均值的两倍; 4. 将生成的红包金额添加到列表中,并更新剩余金额和剩余人数; 5. 最后将剩余金额作为最后一个红包金额添加到列表中; 6. 计算红包总金额,返回红包金额列表。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值