拼手气红包算法,保证金额不会随前后顺序进入而变化,微信的红包生成算法改编

/**
* 拼手气红包算法
*
* @param totalAmount 红包总金额
* @param size 总领取人数
* @param scale 红包金额需要保留的小数位数
* @param minAmount 单个红包的最小金额
* @param remainSize 已领取人数
* @param partitionMoney 已领取金额
*/
private BigDecimal randomHandOutAlgorithm(BigDecimal totalAmount, Integer size, Integer scale,
BigDecimal minAmount, Integer remainSize, BigDecimal partitionMoney) {
BigDecimal resultMoney = new BigDecimal(0);
//剩余红包金额
BigDecimal remainAmount = (totalAmount.subtract(partitionMoney)).setScale(scale,BigDecimal.ROUND_DOWN);
//剩余红包个数
Integer remainSizes = size - remainSize;
if (remainSize+1 != size) {
//前n-1个红包的金额,用随机算法
BigDecimal random = BigDecimal.valueOf(Math.random());
BigDecimal halfRemainSize = BigDecimal.valueOf(remainSizes).divide(new BigDecimal(2), BigDecimal.ROUND_UP);
//计算单次红包的最大值,该算法也是微信的红包算法,可以保证抢红包的期望收益应与先后顺序无关,但后抢红包的方差更大,因此手气最佳更可能在后抢的人中诞生
BigDecimal max1 = remainAmount.divide(halfRemainSize, BigDecimal.ROUND_DOWN);
//同时,最大值需要保证,减去该红包后,剩下的红包足以满足剩余人数的最小金额
BigDecimal minRemainAmount = minAmount.multiply(BigDecimal.valueOf(remainSizes - 1)).setScale(scale, BigDecimal.ROUND_DOWN);
BigDecimal max2 = remainAmount.subtract(minRemainAmount);
//最终,单次红包的最大值等于两个最大值中较小的一个
BigDecimal max = (max1.compareTo(max2) < 0) ? max1 : max2;
resultMoney = random.multiply(max).setScale(scale, BigDecimal.ROUND_DOWN);
//每个红包的数额不能小于预设的最小金额
if (resultMoney.compareTo(minAmount) < 0) {
resultMoney = minAmount;
}
}else {
//最后一个红包,金额等于剩余金额
resultMoney = remainAmount;
}
return resultMoney;
}

相关文章