#碰到一个练习,需要进行红包的随机分配,如此便有此文。
由于红包的特性,也就是红包个数相加要等于红包的总金额、每个红包随机都不可超过红包的总金额等等。
所以每发一个红包就要从总金额中减去。
一、第一个方法
最直白的暴力分配,分一个红包,总金额减去当前红包的金额,最后一个包则拿走剩余的金额,最终完成分配。
例如:红包总金额=10
第一次红包的分母为红包的总金额,也就是10,如果拿走了5元,剩余5元。
第二次红包的分母为红包的剩余总金额,就变成了5,如果再拿走了3元,剩余2元。
第三次、第四次、第五次的基数就会越来越小,有失公平。
/**
* 发红包方法
* 参数1:redPacket为红包总金额
* 参数2:count为红包个数
*
* @param redPacket
* @param count
* @return
*/
public static double[] redPacketDistribution(double redPacket, int count) {
double[] arr = new double[count];//创建一个数组存储结果
Random r = new Random();//创建随机数对象
for (int i = 0; i < count; i++) {//随机红包个数次
if (i + 1 == count) {
arr[i] = redPacket;//拿走剩余总额
redPacket = 0;//总额清零
} else {
double tempResult = r.nextDouble(redPacket);//随机获得一个不超过红包大小的值
String strResult = new DecimalFormat("#.##").format(tempResult);//格式化保留2位
//精准小数运算
BigDecimal bdV = BigDecimal.valueOf(Double.parseDouble(strResult));//当前红包金额
BigDecimal bdRedPacket = BigDecimal.valueOf(redPacket);//红包总额
redPacket = Double.parseDouble(bdRedPacket.subtract(bdV).toString());//红包总金额减去当前红包金额
arr[i] = Double.parseDouble(bdV.toString());
}
}
return arr;
}
运行结果一
运行结果二
运行结果三
结论:通过多次模拟的运行结果以及代码逻辑来看,红包的分配并不均匀,金额大的往往在前。说明此方法的逻辑存在明显问题。
二、第二个方法
第二个方法,参考了热心网友的思路,加以改进,步骤如下。
首先对每个包设定一个随机的值,作为分子,而红包总数的随机值则为分母,简单来讲就是将红包分为若干个不等值。基数我设定为了红包总金额*红包总个数,当然这个基数没有依据,但是我认为不能过大也不能过小,要与红包的总金额和总个数相关,所欲采用这个值为基数。
这个方法的好处我认为是没有领红包的先后顺序,所以不会发生上一种方法那样结果极不均匀的情况,对于每个红包来讲都是公平的。
例如
第1个红包的随机基数为5
第2个红包的随机基数为32
第3个红包的随机基数为47
第4个红包的随机基数为35
第5个红包的随机基数为25
而他们的总基数就为他们的和,也就是144,将红包的总金额平均分为144份,每个红包按照他们的随机基数进行分配。
/**
* 发红包方法
* 参数1:redPacket为红包总金额
* 参数2:count为红包个数
*
* @param redPacket
* @param count
* @return
*/
public static double[] redPacketDistribution(double redPacket, int count) {
double[] arr = new double[count];//创建一个数组存储结果
Random r = new Random();//创建random
int randomSum = 0;//定义随机总值
for (int i = 0; i < count; i++) {//循环获得count个随机值
int res = r.nextInt((int) redPacket * count);//基数为红包总额*红包个数
arr[i] = res;//赋值给结果数组
randomSum += res;//随机总值累加
}
for (int i = 0; i < count; i++) {//循环红包个数次
if (i + 1 == count) {//最后一个包
arr[i] = redPacket;//拿走剩余总额
redPacket = 0;//总额清零
} else {
double tempResult = redPacket * arr[i] / randomSum;//获得随机金额
DecimalFormat df = new DecimalFormat("#.##");//创建格式化
String strResult = df.format(tempResult);//保留2位
double result = Double.parseDouble(strResult);//转回double
//精准小数计算
BigDecimal bdRedPacket = BigDecimal.valueOf(redPacket);
BigDecimal bdResult = BigDecimal.valueOf(result);
redPacket = Double.parseDouble(bdRedPacket.subtract(bdResult).toString());//红包总额=红包总额-此次的随机金额
arr[i] = result;//将此次随机金额放入数组
}
}
return arr;
}
运行结果一
运行结果二
运行结果三
结论:通过多次的模拟结果以及思路,这个方法是相对比较合理的,每个红包获得不同的值的概率基本相同。
2024元旦跨年夜写下此文,祝新年快乐。